~ubuntu-branches/ubuntu/hardy/codeblocks/hardy-backports

« back to all changes in this revision

Viewing changes to src/plugins/astyle/astyle/ASFormatter.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michael Casadevall
  • Date: 2008-07-17 04:39:23 UTC
  • Revision ID: james.westby@ubuntu.com-20080717043923-gmsy5cwkdjswghkm
Tags: upstream-8.02
ImportĀ upstreamĀ versionĀ 8.02

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
2
 *
 
3
 *   ASFormatter.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
#include "astyle.h"
 
30
 
 
31
#include <algorithm>
 
32
#include <fstream>
 
33
#include <iostream>
 
34
#ifdef __VMS
 
35
#include <assert>
 
36
#else
 
37
#include <cassert>
 
38
#endif
 
39
 
 
40
// can trace only if NDEBUG is not defined
 
41
#ifndef NDEBUG
 
42
// #define TRACEunpad
 
43
// #define TRACEcomment
 
44
// #define TRACEheader
 
45
// #define TRACEbracket
 
46
// #define TRACEarray
 
47
#if defined(TRACEunpad) || defined(TRACEcomment) || defined(TRACEheader) \
 
48
|| defined(TRACEbracket) || defined(TRACEarray)
 
49
ofstream *traceOutF;
 
50
#define TRACEF
 
51
#endif
 
52
#endif
 
53
 
 
54
#ifdef TRACEunpad
 
55
#define TRunpad(a,b,c)  if(b > 0 || c > 0) *traceOutF << outLineNumber << " " << b << a << c << endl
 
56
#else
 
57
#define TRunpad(a,b,c)  ((void)0)
 
58
#endif
 
59
 
 
60
#ifdef TRACEcomment
 
61
#define TRcomment(a)    *traceOutF << outLineNumber << " " << a << endl
 
62
#else
 
63
#define TRcomment(a)    ((void)0)
 
64
#endif
 
65
 
 
66
#ifdef TRACEheader
 
67
#define TRxtra(a)       *traceOutF << outLineNumber << " " << a << endl
 
68
#else
 
69
#define TRxtra(a)    ((void)0)
 
70
#endif
 
71
 
 
72
#ifdef TRACEbracket
 
73
#define TRbracket(a)       *traceOutF << outLineNumber << " " << a << endl
 
74
#else
 
75
#define TRbracket(a)    ((void)0)
 
76
#endif
 
77
 
 
78
#ifdef TRACEarray
 
79
#define TRarray(a)      *traceOutF << outLineNumber << " " << a << endl
 
80
#else
 
81
#define TRarray(a)      ((void)0)
 
82
#endif
 
83
 
 
84
#define INIT_CONTAINER(container, value)     {if ( (container) != NULL ) delete (container); (container) = (value); }
 
85
#define DELETE_CONTAINER(container)          {if ( (container) != NULL ) delete (container); }
 
86
#define IS_A(a,b)                            ( ((a) & (b)) == (b))
 
87
 
 
88
using namespace std;
 
89
 
 
90
namespace astyle
 
91
{
 
92
vector<const string*> ASFormatter::headers;
 
93
vector<const string*> ASFormatter::nonParenHeaders;
 
94
vector<const string*> ASFormatter::preDefinitionHeaders;
 
95
vector<const string*> ASFormatter::preCommandHeaders;
 
96
vector<const string*> ASFormatter::operators;
 
97
vector<const string*> ASFormatter::assignmentOperators;
 
98
vector<const string*> ASFormatter::castOperators;
 
99
 
 
100
/**
 
101
 * Constructor of ASFormatter
 
102
 */
 
103
ASFormatter::ASFormatter()
 
104
{
 
105
        preBracketHeaderStack = NULL;
 
106
        bracketTypeStack = NULL;
 
107
        parenStack = NULL;
 
108
        lineCommentNoIndent = false;
 
109
        sourceIterator = NULL;
 
110
        bracketFormatMode = NONE_MODE;
 
111
        shouldPadOperators = false;
 
112
        shouldPadParensOutside = false;
 
113
        shouldPadParensInside = false;
 
114
        shouldUnPadParens = false;
 
115
        shouldBreakOneLineBlocks = true;
 
116
        shouldBreakOneLineStatements = true;
 
117
        shouldConvertTabs = false;
 
118
        shouldBreakBlocks = false;
 
119
        shouldBreakClosingHeaderBlocks = false;
 
120
        shouldBreakClosingHeaderBrackets = false;
 
121
        shouldBreakElseIfs = false;
 
122
#ifdef TRACEF
 
123
        // create a trace text file
 
124
        string filename = "tracef.txt";
 
125
        char* env = getenv("HOME");
 
126
        if (env != NULL)
 
127
                filename = string(env) + string("/tracef.txt");
 
128
        else
 
129
        {
 
130
                env = getenv("USERPROFILE");
 
131
                if (env != NULL)
 
132
                        filename = string(env) + string("\\My Documents\\tracef.txt");
 
133
                else
 
134
                {
 
135
                        cout << "\nCould not open tracef.txt\n" << endl;
 
136
                        exit(1);
 
137
                }
 
138
        }
 
139
        traceOutF = new ofstream(filename.c_str());
 
140
#endif
 
141
}
 
142
 
 
143
/**
 
144
 * Destructor of ASFormatter
 
145
 */
 
146
ASFormatter::~ASFormatter()
 
147
{
 
148
        DELETE_CONTAINER(preBracketHeaderStack);
 
149
#ifdef TRACEF
 
150
        delete traceOutF;
 
151
#endif
 
152
}
 
153
 
 
154
/**
 
155
 * initialization of static data of ASFormatter.
 
156
 */
 
157
void ASFormatter::staticInit()
 
158
{
 
159
        static int formatterFileType = 9;      // initialized with an invalid type
 
160
 
 
161
        if (fileType == formatterFileType)     // don't build unless necessary
 
162
                return;
 
163
 
 
164
        formatterFileType = fileType;
 
165
 
 
166
        headers.clear();
 
167
        nonParenHeaders.clear();
 
168
        assignmentOperators.clear();
 
169
        operators.clear();
 
170
        preDefinitionHeaders.clear();
 
171
        preCommandHeaders.clear();
 
172
        castOperators.clear();
 
173
 
 
174
        ASResource::buildHeaders(headers, fileType);
 
175
        ASResource::buildNonParenHeaders(nonParenHeaders, fileType);
 
176
        ASResource::buildAssignmentOperators(assignmentOperators);
 
177
        ASResource::buildOperators(operators);
 
178
        ASResource::buildPreDefinitionHeaders(preDefinitionHeaders);
 
179
        ASResource::buildPreCommandHeaders(preCommandHeaders);
 
180
        ASResource::buildCastOperators(castOperators);
 
181
}
 
182
 
 
183
/**
 
184
 * initialize the ASFormatter.
 
185
 *
 
186
 * init() should be called every time a ASFormatter object is to start
 
187
 * formatting a NEW source file.
 
188
 * init() recieves a pointer to a DYNAMICALLY CREATED ASSourceIterator object
 
189
 * that will be used to iterate through the source code. This object will be
 
190
 * deleted during the ASFormatter's destruction, and thus should not be
 
191
 * deleted elsewhere.
 
192
 *
 
193
 * @param iter     a pointer to the DYNAMICALLY CREATED ASSourceIterator object.
 
194
 */
 
195
void ASFormatter::init(ASSourceIterator *si)
 
196
{
 
197
        staticInit();
 
198
 
 
199
        ASBeautifier::init(si);
 
200
        ASEnhancer::init(ASBeautifier::getIndentLength(),
 
201
                         ASBeautifier::getIndentString(),
 
202
                         ASBeautifier::getCStyle(),
 
203
                         ASBeautifier::getJavaStyle(),
 
204
                         ASBeautifier::getSharpStyle(),
 
205
                         ASBeautifier::getCaseIndent(),
 
206
                         ASBeautifier::getEmptyLineFill());
 
207
        sourceIterator = si;
 
208
 
 
209
        INIT_CONTAINER(preBracketHeaderStack, new vector<const string*>);
 
210
        INIT_CONTAINER(bracketTypeStack, new vector<BracketType>);
 
211
        bracketTypeStack->push_back(NULL_TYPE);
 
212
        INIT_CONTAINER(parenStack, new vector<int>);
 
213
        parenStack->push_back(0);
 
214
 
 
215
        currentHeader = NULL;
 
216
        currentLine = string("");
 
217
        readyFormattedLine = string("");
 
218
        formattedLine = "";
 
219
        currentChar = ' ';
 
220
        previousChar = ' ';
 
221
        previousCommandChar = ' ';
 
222
        previousNonWSChar = ' ';
 
223
        quoteChar = '"';
 
224
        charNum = 0;
 
225
        spacePadNum = 0;
 
226
        previousReadyFormattedLineLength = string::npos;
 
227
        templateDepth = 0;
 
228
        previousBracketType = NULL_TYPE;
 
229
        previousOperator = NULL;
 
230
 
 
231
        isVirgin = true;
 
232
        isInLineComment = false;
 
233
        isInComment = false;
 
234
        isInPreprocessor = false;
 
235
        doesLineStartComment = false;
 
236
        isInQuote = false;
 
237
        isSpecialChar = false;
 
238
        isNonParenHeader = true;
 
239
        foundNamespaceHeader = false;
 
240
        foundClassHeader = false;
 
241
        foundPreDefinitionHeader = false;
 
242
        foundPreCommandHeader = false;
 
243
        foundCastOperator = false;
 
244
        foundQuestionMark = false;
 
245
        isInLineBreak = false;
 
246
        endOfCodeReached = false;
 
247
        isLineReady = false;
 
248
        isPreviousBracketBlockRelated = true;
 
249
        isInPotentialCalculation = false;
 
250
        shouldReparseCurrentChar = false;
 
251
        passedSemicolon = false;
 
252
        passedColon = false;
 
253
        isInTemplate = false;
 
254
        isInBlParen = false;
 
255
        shouldBreakLineAfterComments = false;
 
256
        isImmediatelyPostComment = false;
 
257
        isImmediatelyPostLineComment = false;
 
258
        isImmediatelyPostEmptyBlock = false;
 
259
        isImmediatelyPostPreprocessor = false;
 
260
 
 
261
        isPrependPostBlockEmptyLineRequested = false;
 
262
        isAppendPostBlockEmptyLineRequested = false;
 
263
        prependEmptyLine = false;
 
264
        appendOpeningBracket = false;
 
265
 
 
266
        foundClosingHeader = false;
 
267
        previousReadyFormattedLineLength = 0;
 
268
 
 
269
        isImmediatelyPostHeader = false;
 
270
        isInHeader = false;
 
271
#ifdef TRACEF
 
272
        // fileName will be empty if ASTYLE_LIB is defined
 
273
        if (fileName.empty())
 
274
                *traceOutF << "new file" << endl;
 
275
        else
 
276
                *traceOutF << fileName << endl;
 
277
#endif
 
278
}
 
279
 
 
280
/**
 
281
 * get the next formatted line.
 
282
 *
 
283
 * @return    formatted line.
 
284
 */
 
285
 
 
286
string ASFormatter::nextLine()
 
287
{
 
288
        // these are reset with each new line
 
289
        const string *newHeader;
 
290
        bool isInVirginLine = isVirgin;
 
291
        isCharImmediatelyPostComment = false;
 
292
        isPreviousCharPostComment = false;
 
293
        isCharImmediatelyPostLineComment = false;
 
294
        isCharImmediatelyPostOpenBlock = false;
 
295
        isCharImmediatelyPostCloseBlock = false;
 
296
        isCharImmediatelyPostTemplate = false;
 
297
 
 
298
        while (!isLineReady)
 
299
        {
 
300
                if (shouldReparseCurrentChar)
 
301
                        shouldReparseCurrentChar = false;
 
302
                else if (!getNextChar())
 
303
                {
 
304
                        breakLine();
 
305
                        return beautify(readyFormattedLine);
 
306
                }
 
307
                else // stuff to do when reading a new character...
 
308
                {
 
309
                        // make sure that a virgin '{' at the begining ofthe file will be treated as a block...
 
310
                        if (isInVirginLine && currentChar == '{')
 
311
                                previousCommandChar = '{';
 
312
                        isPreviousCharPostComment = isCharImmediatelyPostComment;
 
313
                        isCharImmediatelyPostComment = false;
 
314
                        isCharImmediatelyPostTemplate = false;
 
315
                }
 
316
 
 
317
                //if (inLineNumber >= 185)
 
318
                //      int x = 1;
 
319
 
 
320
                if (isInLineComment)
 
321
                {
 
322
                        appendCurrentChar();
 
323
 
 
324
                        // explicitely break a line when a line comment's end is found.
 
325
                        if (charNum + 1 == (int) currentLine.length())
 
326
                        {
 
327
                                isInLineBreak = true;
 
328
                                isInLineComment = false;
 
329
                                isImmediatelyPostLineComment = true;
 
330
                                currentChar = 0;  //make sure it is a neutral char.
 
331
                        }
 
332
                        continue;
 
333
                }
 
334
                else if (isInComment)
 
335
                {
 
336
                        if (isSequenceReached("*/"))
 
337
                        {
 
338
                                isInComment = false;
 
339
                                isImmediatelyPostComment = true;
 
340
                                appendSequence(AS_CLOSE_COMMENT);
 
341
                                goForward(1);
 
342
                        }
 
343
                        else
 
344
                                appendCurrentChar();
 
345
 
 
346
                        continue;
 
347
                }
 
348
 
 
349
                // not in line comment or comment
 
350
 
 
351
                else if (isInQuote)
 
352
                {
 
353
                        if (isSpecialChar)
 
354
                        {
 
355
                                isSpecialChar = false;
 
356
                                appendCurrentChar();
 
357
                        }
 
358
                        else if (currentChar == '\\')
 
359
                        {
 
360
                                isSpecialChar = true;
 
361
                                appendCurrentChar();
 
362
                        }
 
363
                        else if (quoteChar == currentChar)
 
364
                        {
 
365
                                isInQuote = false;
 
366
                                appendCurrentChar();
 
367
                        }
 
368
                        else
 
369
                        {
 
370
                                appendCurrentChar();
 
371
                        }
 
372
 
 
373
                        continue;
 
374
                }
 
375
 
 
376
                // handle white space - needed to simplify the rest.
 
377
                if (isWhiteSpace(currentChar) || isInPreprocessor)
 
378
                {
 
379
                        appendCurrentChar();
 
380
                        continue;
 
381
                }
 
382
 
 
383
                /* not in MIDDLE of quote or comment or white-space of any type ... */
 
384
 
 
385
                if (isSequenceReached("//"))
 
386
                {
 
387
                        if (currentLine[charNum+2] == '\xf2')           // check for windows line marker
 
388
                                isAppendPostBlockEmptyLineRequested = false;
 
389
                        isInLineComment = true;
 
390
                        // do not indent if in column 1 or 2
 
391
                        if (lineCommentNoIndent == false)
 
392
                        {
 
393
                                if (charNum == 0)
 
394
                                        lineCommentNoIndent = true;
 
395
                                else if (charNum == 1 && currentLine[0] == ' ')
 
396
                                        lineCommentNoIndent = true;
 
397
                        }
 
398
                        // move comment if spaces were added or deleted
 
399
                        if (lineCommentNoIndent == false && spacePadNum != 0)
 
400
                                adjustComments();
 
401
                        formattedLineCommentNum = formattedLine.length();
 
402
                        appendSequence(AS_OPEN_LINE_COMMENT);
 
403
                        goForward(1);
 
404
                        // explicitely break a line when a line comment's end is found.
 
405
                        if (charNum + 1 == (int) currentLine.length())
 
406
                        {
 
407
                                isInLineBreak = true;
 
408
                                isInLineComment = false;
 
409
                                isImmediatelyPostLineComment = true;
 
410
                                currentChar = 0;  //make sure it is a neutral char.
 
411
                        }
 
412
                        continue;
 
413
                }
 
414
                else if (isSequenceReached("/*"))
 
415
                {
 
416
                        isInComment = true;
 
417
                        if (spacePadNum != 0)
 
418
                                adjustComments();
 
419
                        formattedLineCommentNum = formattedLine.length();
 
420
                        appendSequence(AS_OPEN_COMMENT);
 
421
                        goForward(1);
 
422
                        continue;
 
423
                }
 
424
                else if (currentChar == '"' || currentChar == '\'')
 
425
                {
 
426
                        isInQuote = true;
 
427
                        quoteChar = currentChar;
 
428
                        appendCurrentChar();
 
429
                        continue;
 
430
                }
 
431
 
 
432
                /* not in quote or comment or white-space of any type ... */
 
433
 
 
434
                // check if in preprocessor
 
435
                // ** isInPreprocessor will be automatically reset at the begining
 
436
                //    of a new line in getnextChar()
 
437
                if (currentChar == '#')
 
438
                {
 
439
                        isInPreprocessor = true;
 
440
                        appendCurrentChar();
 
441
                        continue;
 
442
                }
 
443
 
 
444
                /* not in preprocessor ... */
 
445
 
 
446
                if (isImmediatelyPostComment)
 
447
                {
 
448
                        isImmediatelyPostComment = false;
 
449
                        isCharImmediatelyPostComment = true;
 
450
                }
 
451
 
 
452
                if (isImmediatelyPostLineComment)
 
453
                {
 
454
                        isImmediatelyPostLineComment = false;
 
455
                        isCharImmediatelyPostLineComment = true;
 
456
                }
 
457
 
 
458
                if (shouldBreakLineAfterComments)
 
459
                {
 
460
                        shouldBreakLineAfterComments = false;
 
461
                        shouldReparseCurrentChar = true;
 
462
                        breakLine();
 
463
                        continue;
 
464
                }
 
465
 
 
466
                // reset isImmediatelyPostHeader information
 
467
                if (isImmediatelyPostHeader)
 
468
                {
 
469
                        isImmediatelyPostHeader = false;
 
470
 
 
471
                        // Make sure headers are broken from their succeeding blocks
 
472
                        // (e.g.
 
473
                        //     if (isFoo) DoBar();
 
474
                        //  should become
 
475
                        //     if (isFoo)
 
476
                        //         DoBar;
 
477
                        // )
 
478
                        // But treat else if() as a special case which should not be broken!
 
479
                        if (shouldBreakOneLineStatements)
 
480
                        {
 
481
                                // if may break 'else if()'s, then simply break the line
 
482
 
 
483
                                if (shouldBreakElseIfs)
 
484
                                        isInLineBreak = true;
 
485
                        }
 
486
                }
 
487
 
 
488
                if (passedSemicolon)    // need to break the formattedLine
 
489
                {
 
490
                        passedSemicolon = false;
 
491
                        if (parenStack->back() == 0 && currentChar != ';') // allow ;;
 
492
                        {
 
493
                                // does a one-line statement have ending comments?
 
494
                                if (IS_A(bracketTypeStack->back(), SINGLE_LINE_TYPE))
 
495
                                {
 
496
                                        size_t blockEnd = currentLine.rfind(AS_CLOSE_BRACKET);
 
497
                                        assert(blockEnd != string::npos);
 
498
                                        // move ending comments to this formattedLine
 
499
                                        if (isBeforeLineEndComment(blockEnd))
 
500
                                        {
 
501
                                                size_t commentStart = currentLine.find_first_not_of(" \t", blockEnd + 1);
 
502
                                                assert(commentStart != string::npos);
 
503
                                                assert((currentLine.compare(commentStart, 2, "//") == 0)
 
504
                                                       || (currentLine.compare(commentStart, 2, "/*") == 0));
 
505
                                                size_t commentLength = currentLine.length() - commentStart;
 
506
                                                int tabCount = getIndentLength();
 
507
                                                appendSpacePad();
 
508
                                                for (int i=1; i<tabCount; i++)
 
509
                                                        formattedLine.append(1, ' ');
 
510
                                                formattedLine.append(currentLine, commentStart, commentLength);
 
511
                                                currentLine.erase(commentStart, commentLength);
 
512
                                        }
 
513
                                }
 
514
                                shouldReparseCurrentChar = true;
 
515
                                isInLineBreak = true;
 
516
                                continue;
 
517
                        }
 
518
                }
 
519
 
 
520
                if (passedColon)
 
521
                {
 
522
                        passedColon = false;
 
523
                        if (parenStack->back() == 0 && !isBeforeComment())
 
524
                        {
 
525
                                shouldReparseCurrentChar = true;
 
526
                                isInLineBreak = true;
 
527
                                continue;
 
528
                        }
 
529
                }
 
530
 
 
531
                // Check if in template declaration, e.g. foo<bar> or foo<bar,fig>
 
532
                // If so, set isInTemplate to true
 
533
                if (!isInTemplate && currentChar == '<')
 
534
                {
 
535
                        int maxTemplateDepth = 0;
 
536
                        templateDepth = 0;
 
537
                        const string *oper;
 
538
                        for (size_t i = charNum;
 
539
                                i < currentLine.length();
 
540
                                i += (oper ? oper->length() : 1))
 
541
                        {
 
542
                                oper = ASBeautifier::findHeader(currentLine, i, operators);
 
543
 
 
544
                                if (oper == &AS_LS)
 
545
                                {
 
546
                                        templateDepth++;
 
547
                                        maxTemplateDepth++;
 
548
                                }
 
549
                                else if (oper == &AS_GR)
 
550
                                {
 
551
                                        templateDepth--;
 
552
                                        if (templateDepth == 0)
 
553
                                        {
 
554
                                                // this is a template!
 
555
                                                isInTemplate = true;
 
556
                                                templateDepth = maxTemplateDepth;
 
557
                                                break;
 
558
                                        }
 
559
                                }
 
560
                                else if (oper == &AS_COMMA            // comma,     e.g. A<int, char>
 
561
                                         || oper == &AS_BIT_AND       // reference, e.g. A<int&>
 
562
                                         || oper == &AS_MULT          // pointer,   e.g. A<int*>
 
563
                                         || oper == &AS_COLON_COLON)  // ::,        e.g. std::string
 
564
                                {
 
565
                                        continue;
 
566
                                }
 
567
                                else if (!isLegalNameChar(currentLine[i]) && !isWhiteSpace(currentLine[i]))
 
568
                                {
 
569
                                        // this is not a template -> leave...
 
570
                                        isInTemplate = false;
 
571
                                        break;
 
572
                                }
 
573
                        }
 
574
                }
 
575
 
 
576
                // handle parenthesies
 
577
                if (currentChar == '(' || currentChar == '[' || (isInTemplate && currentChar == '<'))
 
578
                {
 
579
                        parenStack->back()++;
 
580
                        if (currentChar == '[')
 
581
                                isInBlParen = true;
 
582
                }
 
583
                else if (currentChar == ')' || currentChar == ']' || (isInTemplate && currentChar == '>'))
 
584
                {
 
585
                        parenStack->back()--;
 
586
                        if (isInTemplate && currentChar == '>')
 
587
                        {
 
588
                                templateDepth--;
 
589
                                if (templateDepth == 0)
 
590
                                {
 
591
                                        isInTemplate = false;
 
592
                                        isCharImmediatelyPostTemplate = true;
 
593
                                }
 
594
                        }
 
595
 
 
596
                        // check if this parenthesis closes a header, e.g. if (...), while (...)
 
597
                        if (isInHeader && parenStack->back() == 0)
 
598
                        {
 
599
                                isInHeader = false;
 
600
                                isImmediatelyPostHeader = true;
 
601
                        }
 
602
                        if (currentChar == ']')
 
603
                                isInBlParen = false;
 
604
                        if (currentChar == ')')
 
605
                                foundCastOperator = false;
 
606
                }
 
607
 
 
608
                // handle brackets
 
609
                if (currentChar == '{' || currentChar == '}')
 
610
                {
 
611
                        if (currentChar == '{')
 
612
                        {
 
613
                                BracketType newBracketType = getBracketType();
 
614
                                foundNamespaceHeader = false;
 
615
                                foundClassHeader = false;
 
616
                                foundPreDefinitionHeader = false;
 
617
                                foundPreCommandHeader = false;
 
618
                                isInPotentialCalculation = false;
 
619
 
 
620
                                bracketTypeStack->push_back(newBracketType);
 
621
                                preBracketHeaderStack->push_back(currentHeader);
 
622
                                currentHeader = NULL;
 
623
 
 
624
                                isPreviousBracketBlockRelated = !IS_A(newBracketType, ARRAY_TYPE);
 
625
                        }
 
626
 
 
627
                        // this must be done before the bracketTypeStack is popped
 
628
                        BracketType bracketType = bracketTypeStack->back();
 
629
                        bool isOpeningArrayBracket = (IS_A(bracketType, ARRAY_TYPE)
 
630
                                                      && bracketTypeStack->size() >= 2
 
631
                                                      && !IS_A((*bracketTypeStack)[bracketTypeStack->size()-2], ARRAY_TYPE)
 
632
                                                     );
 
633
 
 
634
                        if (currentChar == '}')
 
635
                        {
 
636
                                // if a request has been made to append a post block empty line,
 
637
                                // but the block exists immediately before a closing bracket,
 
638
                                // then there is not need for the post block empty line.
 
639
                                //
 
640
                                isAppendPostBlockEmptyLineRequested = false;
 
641
 
 
642
                                if (!bracketTypeStack->empty())
 
643
                                {
 
644
                                        previousBracketType = bracketTypeStack->back();
 
645
                                        bracketTypeStack->pop_back();
 
646
                                        isPreviousBracketBlockRelated = !IS_A(bracketType, ARRAY_TYPE);
 
647
                                }
 
648
 
 
649
                                if (!preBracketHeaderStack->empty())
 
650
                                {
 
651
                                        currentHeader = preBracketHeaderStack->back();
 
652
                                        preBracketHeaderStack->pop_back();
 
653
                                }
 
654
                                else
 
655
                                        currentHeader = NULL;
 
656
                        }
 
657
 
 
658
                        // format brackets
 
659
                        if (IS_A(bracketType, ARRAY_TYPE))
 
660
                                formatArrayBrackets(bracketType, isOpeningArrayBracket);
 
661
                        else
 
662
                                formatBrackets(bracketType);
 
663
                        continue;
 
664
                }
 
665
 
 
666
                if (((previousCommandChar == '{' && isPreviousBracketBlockRelated)
 
667
                        || (previousCommandChar == '}'
 
668
                            && bracketFormatMode != NONE_MODE
 
669
                            && !isImmediatelyPostEmptyBlock
 
670
                            && isPreviousBracketBlockRelated
 
671
                            && !isPreviousCharPostComment       // Fixes wrongly appended newlines after '}' immediately after comments
 
672
                            && peekNextChar() != ' '
 
673
                            && !IS_A(previousBracketType,  DEFINITION_TYPE)
 
674
                            && !(ASBeautifier::isJavaStyle && currentChar == ')'))
 
675
                        && !IS_A(bracketTypeStack->back(),  DEFINITION_TYPE))
 
676
                        && (shouldBreakOneLineBlocks
 
677
                            || !IS_A(bracketTypeStack->back(),  SINGLE_LINE_TYPE)))
 
678
                {
 
679
                        isCharImmediatelyPostOpenBlock = (previousCommandChar == '{');
 
680
                        isCharImmediatelyPostCloseBlock = (previousCommandChar == '}');
 
681
 
 
682
                        //if (bracketFormatMode != NONE_MODE)
 
683
                        //{
 
684
                        previousCommandChar = ' ';
 
685
                        isInLineBreak = true;
 
686
                        //}
 
687
                }
 
688
 
 
689
                // reset block handling flags
 
690
                isImmediatelyPostEmptyBlock = false;
 
691
 
 
692
                // look for headers
 
693
                if (!isInTemplate)
 
694
                {
 
695
                        if ((newHeader = findHeader(headers)) != NULL)
 
696
                        {
 
697
                                foundClosingHeader = false;
 
698
                                const string *previousHeader;
 
699
 
 
700
                                // recognize closing headers of do..while, if..else, try..catch..finally
 
701
                                if ((newHeader == &AS_ELSE && currentHeader == &AS_IF)
 
702
                                        || (newHeader == &AS_WHILE && currentHeader == &AS_DO)
 
703
                                        || (newHeader == &AS_CATCH && currentHeader == &AS_TRY)
 
704
                                        || (newHeader == &AS_CATCH && currentHeader == &AS_CATCH)
 
705
                                        || (newHeader == &AS_FINALLY && currentHeader == &AS_TRY)
 
706
                                        || (newHeader == &AS_FINALLY && currentHeader == &AS_CATCH))
 
707
                                        foundClosingHeader = true;
 
708
 
 
709
                                previousHeader = currentHeader;
 
710
                                currentHeader = newHeader;
 
711
 
 
712
                                // If in ATTACH or LINUX bracket modes, attach closing headers (e.g. 'else', 'catch')
 
713
                                // to their preceding bracket,
 
714
                                // But do not perform the attachment if the shouldBreakClosingHeaderBrackets is set!
 
715
                                if (!shouldBreakClosingHeaderBrackets
 
716
                                        && foundClosingHeader
 
717
                                        && (bracketFormatMode == ATTACH_MODE || bracketFormatMode == BDAC_MODE)
 
718
                                        && (shouldBreakOneLineBlocks || !IS_A(previousBracketType,  SINGLE_LINE_TYPE))
 
719
                                        && previousNonWSChar == '}')
 
720
                                {
 
721
                                        spacePadNum = 0;                // don't count as padding
 
722
 
 
723
                                        size_t firstChar = formattedLine.find_first_not_of(" \t");
 
724
                                        if (firstChar != string::npos)          // if a blank line does not preceed this
 
725
                                        {
 
726
                                                isInLineBreak = false;
 
727
                                                appendSpacePad();
 
728
                                        }
 
729
 
 
730
                                        if (shouldBreakBlocks)
 
731
                                                isAppendPostBlockEmptyLineRequested = false;
 
732
                                }
 
733
 
 
734
                                // If NONE bracket mode, leave closing headers as they are (e.g. 'else', 'catch')
 
735
                                if (foundClosingHeader && bracketFormatMode == NONE_MODE && previousCommandChar == '}')
 
736
                                {
 
737
                                        if (lineBeginsWith('}'))                    // is closing bracket broken?
 
738
                                        {
 
739
                                                isInLineBreak = false;
 
740
                                                appendSpacePad();
 
741
                                        }
 
742
 
 
743
                                        if (shouldBreakBlocks)
 
744
                                                isAppendPostBlockEmptyLineRequested = false;
 
745
                                }
 
746
 
 
747
                                if (foundClosingHeader && bracketFormatMode == BREAK_MODE && previousCommandChar == '}')
 
748
                                        breakLine();
 
749
 
 
750
                                //Check if a template definition as been reached, e.g. template<class A>
 
751
                                //if (newHeader == &AS_TEMPLATE)
 
752
                                //{
 
753
                                //      isInTemplate = true;
 
754
                                //}
 
755
 
 
756
                                // check if the found header is non-paren header
 
757
                                isNonParenHeader = (find(nonParenHeaders.begin(), nonParenHeaders.end(),
 
758
                                                         newHeader) != nonParenHeaders.end());
 
759
 
 
760
                                appendSequence(*currentHeader);
 
761
                                goForward(currentHeader->length() - 1);
 
762
                                // if a paren-header is found add a space after it, if needed
 
763
                                // this checks currentLine, appendSpacePad() checks formattedLine
 
764
                                if (!isNonParenHeader && charNum < (int) currentLine.length() && !isWhiteSpace(currentLine[charNum+1]))
 
765
                                        appendSpacePad();
 
766
 
 
767
                                // Signal that a header has been reached
 
768
                                // *** But treat a closing while() (as in do...while)
 
769
                                //     as if it where NOT a header since a closing while()
 
770
                                //     should never have a block after it!
 
771
                                if (!(foundClosingHeader && currentHeader == &AS_WHILE))
 
772
                                {
 
773
                                        isInHeader = true;
 
774
                                        if (isNonParenHeader)
 
775
                                        {
 
776
                                                isImmediatelyPostHeader = true;
 
777
                                                isInHeader = false;
 
778
                                        }
 
779
                                }
 
780
 
 
781
                                if (currentHeader == &AS_IF && previousHeader == &AS_ELSE)
 
782
                                        isInLineBreak = false;
 
783
 
 
784
                                if (shouldBreakBlocks)
 
785
                                {
 
786
                                        if (previousHeader == NULL
 
787
                                                && !foundClosingHeader
 
788
                                                && !isCharImmediatelyPostOpenBlock)
 
789
                                        {
 
790
                                                isPrependPostBlockEmptyLineRequested = true;
 
791
                                        }
 
792
 
 
793
                                        if (currentHeader == &AS_ELSE
 
794
                                                || currentHeader == &AS_CATCH
 
795
                                                || currentHeader == &AS_FINALLY
 
796
                                                || foundClosingHeader)
 
797
                                        {
 
798
                                                isPrependPostBlockEmptyLineRequested = false;
 
799
                                        }
 
800
 
 
801
                                        if (shouldBreakClosingHeaderBlocks
 
802
                                                &&  isCharImmediatelyPostCloseBlock)
 
803
                                        {
 
804
                                                isPrependPostBlockEmptyLineRequested = true;
 
805
                                        }
 
806
 
 
807
                                }
 
808
 
 
809
                                continue;
 
810
                        }
 
811
                        else if ((newHeader = findHeader(preDefinitionHeaders)) != NULL
 
812
                                 && parenStack->back() == 0)
 
813
                        {
 
814
                                if (newHeader == &AS_NAMESPACE)
 
815
                                        foundNamespaceHeader = true;
 
816
                                if (newHeader == &AS_CLASS)
 
817
                                        foundClassHeader = true;
 
818
                                foundPreDefinitionHeader = true;
 
819
                                appendSequence(*newHeader);
 
820
                                goForward(newHeader->length() - 1);
 
821
 
 
822
                                if (shouldBreakBlocks)
 
823
                                        isPrependPostBlockEmptyLineRequested = true;
 
824
 
 
825
                                continue;
 
826
                        }
 
827
                        else if ((newHeader = findHeader(preCommandHeaders)) != NULL)
 
828
                        {
 
829
                                if (ASBeautifier::isJavaStyle
 
830
                                        || (*newHeader == AS_CONST && previousCommandChar == ')') // 'const' member functions is a command bracket
 
831
                                        || *newHeader == AS_EXTERN)
 
832
                                        foundPreCommandHeader = true;
 
833
                                appendSequence(*newHeader);
 
834
                                goForward(newHeader->length() - 1);
 
835
 
 
836
                                continue;
 
837
                        }
 
838
                        else if ((newHeader = findHeader(castOperators)) != NULL)
 
839
                        {
 
840
                                foundCastOperator = true;
 
841
                                appendSequence(*newHeader);
 
842
                                goForward(newHeader->length() - 1);
 
843
 
 
844
                                continue;
 
845
                        }
 
846
 
 
847
                }
 
848
 
 
849
                if (isInLineBreak)          // OK to break line here
 
850
                        breakLine();
 
851
 
 
852
                if (previousNonWSChar == '}' || currentChar == ';')
 
853
                {
 
854
                        if (shouldBreakOneLineStatements && currentChar == ';'
 
855
                                && (shouldBreakOneLineBlocks || !IS_A(bracketTypeStack->back(),  SINGLE_LINE_TYPE))
 
856
                                //&& (! bracketFormatMode == NONE_MODE)
 
857
                           )
 
858
                        {
 
859
                                passedSemicolon = true;
 
860
                        }
 
861
 
 
862
                        if (shouldBreakBlocks && currentHeader != NULL && parenStack->back() == 0)
 
863
                        {
 
864
                                isAppendPostBlockEmptyLineRequested = true;
 
865
                        }
 
866
 
 
867
                        if (currentChar != ';')
 
868
                                currentHeader = NULL;
 
869
 
 
870
                        foundQuestionMark = false;
 
871
                        foundNamespaceHeader = false;
 
872
                        foundClassHeader = false;
 
873
                        foundPreDefinitionHeader = false;
 
874
                        foundPreCommandHeader = false;
 
875
                        foundCastOperator = false;
 
876
                        isInPotentialCalculation = false;
 
877
                        isNonInStatementArray = false;
 
878
                }
 
879
 
 
880
                if (currentChar == ':'
 
881
                        && shouldBreakOneLineStatements
 
882
                        && !foundQuestionMark           // not in a ... ? ... : ... sequence
 
883
                        && !foundPreDefinitionHeader    // not in a definition block (e.g. class foo : public bar
 
884
                        && previousCommandChar != ')'   // not immediately after closing paren of a method header, e.g. ASFormatter::ASFormatter(...) : ASBeautifier(...)
 
885
                        && previousChar != ':'          // not part of '::'
 
886
                        && peekNextChar() != ':')       // not part of '::'
 
887
                {
 
888
                        passedColon = true;
 
889
                        if (shouldBreakBlocks)
 
890
                                isPrependPostBlockEmptyLineRequested = true;
 
891
                }
 
892
 
 
893
                if (currentChar == '?')
 
894
                        foundQuestionMark = true;
 
895
 
 
896
                // determine if this is a potential calculation
 
897
                newHeader = findHeader(operators);
 
898
 
 
899
                if (newHeader != NULL)
 
900
                {
 
901
                        if (!isInPotentialCalculation)
 
902
                        {
 
903
                                if (find(assignmentOperators.begin(), assignmentOperators.end(), newHeader)
 
904
                                        != assignmentOperators.end())
 
905
                                {
 
906
                                        char peekedChar = peekNextChar();
 
907
                                        isInPotentialCalculation = (newHeader != &AS_RETURN
 
908
                                                                    && !(newHeader == &AS_EQUAL && peekedChar == '*')
 
909
                                                                    && !(newHeader == &AS_EQUAL && peekedChar == '&'));
 
910
                                }
 
911
                        }
 
912
                }
 
913
                else
 
914
                {
 
915
                        // the following are not calculations
 
916
                        if (currentLine.compare(charNum, 3, "new") == 0 && !isLegalNameChar(currentLine[charNum+3]))
 
917
                                isInPotentialCalculation = false;
 
918
                }
 
919
 
 
920
                if (shouldPadOperators && newHeader != NULL)
 
921
                {
 
922
                        padOperators(newHeader);
 
923
                        continue;
 
924
                }
 
925
 
 
926
                if ((shouldPadParensOutside || shouldPadParensInside || shouldUnPadParens)
 
927
                        && (currentChar == '(' || currentChar == ')'))
 
928
                {
 
929
                        padParens();
 
930
                        continue;
 
931
                }
 
932
 
 
933
                appendCurrentChar();
 
934
        }   // end of while loop  *  end of while loop  *  end of while loop  *  end of while loop
 
935
 
 
936
        // return a beautified (i.e. correctly indented) line.
 
937
 
 
938
        string beautifiedLine;
 
939
        size_t readyFormattedLineLength = trim(readyFormattedLine).length();
 
940
 
 
941
        if (prependEmptyLine                // prepend a blank line before this formatted line
 
942
                && readyFormattedLineLength > 0
 
943
                && previousReadyFormattedLineLength > 0)
 
944
        {
 
945
                isLineReady = true;             // signal that a readyFormattedLine is still waiting
 
946
                beautifiedLine = beautify("");
 
947
                previousReadyFormattedLineLength = 0;
 
948
        }
 
949
        else                                                            // format the current formatted line
 
950
        {
 
951
                isLineReady = false;
 
952
                beautifiedLine = beautify(readyFormattedLine);
 
953
                previousReadyFormattedLineLength = readyFormattedLineLength;
 
954
                lineCommentNoBeautify = lineCommentNoIndent;
 
955
                lineCommentNoIndent = false;
 
956
                if (appendOpeningBracket)       // insert bracket after this formatted line
 
957
                {
 
958
                        appendOpeningBracket = false;
 
959
                        isLineReady = true;         // signal that a readyFormattedLine is still waiting
 
960
                        readyFormattedLine = "{";
 
961
                        isPrependPostBlockEmptyLineRequested = false;   // next line should not be empty
 
962
                }
 
963
        }
 
964
 
 
965
        prependEmptyLine = false;
 
966
        enhance(beautifiedLine);                // call the enhancer function
 
967
        return beautifiedLine;
 
968
}
 
969
 
 
970
 
 
971
/**
 
972
* check if there are any indented lines ready to be read by nextLine()
 
973
*
 
974
* @return    are there any indented lines ready?
 
975
*/
 
976
bool ASFormatter::hasMoreLines() const
 
977
{
 
978
        return !endOfCodeReached;
 
979
}
 
980
 
 
981
/**
 
982
 * set the bracket formatting mode.
 
983
 * options:
 
984
 *    astyle::NONE_MODE     no formatting of brackets.
 
985
 *    astyle::ATTACH_MODE   Java, K&R style bracket placement.
 
986
 *    astyle::BREAK_MODE    ANSI C/C++ style bracket placement.
 
987
 *
 
988
 * @param mode         the bracket formatting mode.
 
989
 */
 
990
void ASFormatter::setBracketFormatMode(BracketMode mode)
 
991
{
 
992
        bracketFormatMode = mode;
 
993
}
 
994
 
 
995
/**
 
996
 * set closing header bracket breaking mode
 
997
 * options:
 
998
 *    true     brackets just before closing headers (e.g. 'else', 'catch')
 
999
 *             will be broken, even if standard brackets are attached.
 
1000
 *    false    closing header brackets will be treated as standard brackets.
 
1001
 *
 
1002
 * @param state         the closing header bracket breaking mode.
 
1003
 */
 
1004
void ASFormatter::setBreakClosingHeaderBracketsMode(bool state)
 
1005
{
 
1006
        shouldBreakClosingHeaderBrackets = state;
 
1007
}
 
1008
 
 
1009
/**
 
1010
 * set 'else if()' breaking mode
 
1011
 * options:
 
1012
 *    true     'else' headers will be broken from their succeeding 'if' headers.
 
1013
 *    false    'else' headers will be attached to their succeeding 'if' headers.
 
1014
 *
 
1015
 * @param state         the 'else if()' breaking mode.
 
1016
 */
 
1017
void ASFormatter::setBreakElseIfsMode(bool state)
 
1018
{
 
1019
        shouldBreakElseIfs = state;
 
1020
}
 
1021
 
 
1022
/**
 
1023
 * set operator padding mode.
 
1024
 * options:
 
1025
 *    true     statement operators will be padded with spaces around them.
 
1026
 *    false    statement operators will not be padded.
 
1027
 *
 
1028
 * @param state         the padding mode.
 
1029
 */
 
1030
void ASFormatter::setOperatorPaddingMode(bool state)
 
1031
{
 
1032
        shouldPadOperators = state;
 
1033
}
 
1034
 
 
1035
/**
 
1036
* set parenthesis outside padding mode.
 
1037
* options:
 
1038
*    true     statement parenthesiss will be padded with spaces around them.
 
1039
*    false    statement parenthesiss will not be padded.
 
1040
*
 
1041
* @param state         the padding mode.
 
1042
*/
 
1043
void ASFormatter::setParensOutsidePaddingMode(bool state)
 
1044
{
 
1045
        shouldPadParensOutside = state;
 
1046
}
 
1047
 
 
1048
/**
 
1049
* set parenthesis inside padding mode.
 
1050
* options:
 
1051
*    true     statement parenthesis will be padded with spaces around them.
 
1052
*    false    statement parenthesis will not be padded.
 
1053
*
 
1054
* @param state         the padding mode.
 
1055
*/
 
1056
void ASFormatter::setParensInsidePaddingMode(bool state)
 
1057
{
 
1058
        shouldPadParensInside = state;
 
1059
}
 
1060
 
 
1061
/**
 
1062
* set parenthesis unpadding mode.
 
1063
* options:
 
1064
*    true     statement parenthesis will be unpadded with spaces removed around them.
 
1065
*    false    statement parenthesis will not be unpadded.
 
1066
*
 
1067
* @param state         the padding mode.
 
1068
*/
 
1069
void ASFormatter::setParensUnPaddingMode(bool state)
 
1070
{
 
1071
        shouldUnPadParens = state;
 
1072
}
 
1073
 
 
1074
/**
 
1075
 * set option to break/not break one-line blocks
 
1076
 *
 
1077
 * @param state        true = break, false = don't break.
 
1078
 */
 
1079
void ASFormatter::setBreakOneLineBlocksMode(bool state)
 
1080
{
 
1081
        shouldBreakOneLineBlocks = state;
 
1082
}
 
1083
 
 
1084
/**
 
1085
 * set option to break/not break lines consisting of multiple statements.
 
1086
 *
 
1087
 * @param state        true = break, false = don't break.
 
1088
 */
 
1089
void ASFormatter::setSingleStatementsMode(bool state)
 
1090
{
 
1091
        shouldBreakOneLineStatements = state;
 
1092
}
 
1093
 
 
1094
/**
 
1095
 * set option to convert tabs to spaces.
 
1096
 *
 
1097
 * @param state        true = convert, false = don't convert.
 
1098
 */
 
1099
void ASFormatter::setTabSpaceConversionMode(bool state)
 
1100
{
 
1101
        shouldConvertTabs = state;
 
1102
}
 
1103
 
 
1104
 
 
1105
/**
 
1106
 * set option to break unrelated blocks of code with empty lines.
 
1107
 *
 
1108
 * @param state        true = convert, false = don't convert.
 
1109
 */
 
1110
void ASFormatter::setBreakBlocksMode(bool state)
 
1111
{
 
1112
        shouldBreakBlocks = state;
 
1113
}
 
1114
 
 
1115
/**
 
1116
 * set option to break closing header blocks of code (such as 'else', 'catch', ...) with empty lines.
 
1117
 *
 
1118
 * @param state        true = convert, false = don't convert.
 
1119
 */
 
1120
void ASFormatter::setBreakClosingHeaderBlocksMode(bool state)
 
1121
{
 
1122
        shouldBreakClosingHeaderBlocks = state;
 
1123
}
 
1124
 
 
1125
/**
 
1126
 * jump over several characters.
 
1127
 *
 
1128
 * @param i       the number of characters to jump over.
 
1129
 */
 
1130
void ASFormatter::goForward(int i)
 
1131
{
 
1132
        while (--i >= 0)
 
1133
                getNextChar();
 
1134
}
 
1135
 
 
1136
/**
 
1137
* peek at the next unread character.
 
1138
*
 
1139
* @return     the next unread character.
 
1140
*/
 
1141
char ASFormatter::peekNextChar() const
 
1142
{
 
1143
        char ch = ' ';
 
1144
        size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);
 
1145
 
 
1146
        if (peekNum == string::npos)
 
1147
                return ch;
 
1148
 
 
1149
        ch = currentLine[peekNum];
 
1150
 
 
1151
//      if (shouldConvertTabs && ch == '\t')
 
1152
//              ch = ' ';
 
1153
 
 
1154
        return ch;
 
1155
}
 
1156
 
 
1157
/**
 
1158
* check if current placement is before a comment or line-comment
 
1159
*
 
1160
* @return     is before a comment or line-comment.
 
1161
*/
 
1162
bool ASFormatter::isBeforeComment() const
 
1163
{
 
1164
        bool foundComment = false;
 
1165
        size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);
 
1166
 
 
1167
        if (peekNum == string::npos)
 
1168
                return foundComment;
 
1169
 
 
1170
        foundComment = (currentLine.compare(peekNum, 2, "/*") == 0
 
1171
                        || currentLine.compare(peekNum, 2, "//") == 0);
 
1172
 
 
1173
        return foundComment;
 
1174
}
 
1175
 
 
1176
/**
 
1177
* check if current placement is before a comment or line-comment
 
1178
* if a block comment it must be at the end of the line
 
1179
*
 
1180
* @return     is before a comment or line-comment.
 
1181
*/
 
1182
bool ASFormatter::isBeforeLineEndComment(int startPos) const
 
1183
{
 
1184
        bool foundLineEndComment = false;
 
1185
        size_t peekNum = currentLine.find_first_not_of(" \t", startPos + 1);
 
1186
 
 
1187
        if (peekNum != string::npos)
 
1188
        {
 
1189
                if (currentLine.compare(peekNum, 2, "//") == 0)
 
1190
                        foundLineEndComment = true;
 
1191
                else if (currentLine.compare(peekNum, 2, "/*") == 0)
 
1192
                {
 
1193
                        // comment must be closed on this line with nothing after it
 
1194
                        size_t endNum = currentLine.find("*/", peekNum + 2);
 
1195
                        if (endNum != string::npos)
 
1196
                                if (currentLine.find_first_not_of(" \t", endNum + 2) == string::npos)
 
1197
                                        foundLineEndComment = true;
 
1198
                }
 
1199
        }
 
1200
        return foundLineEndComment;
 
1201
}
 
1202
 
 
1203
 
 
1204
/**
 
1205
* get the next character, increasing the current placement in the process.
 
1206
* the new character is inserted into the variable currentChar.
 
1207
*
 
1208
* @return   whether succeded to recieve the new character.
 
1209
*/
 
1210
bool ASFormatter::getNextChar()
 
1211
{
 
1212
        isInLineBreak = false;
 
1213
        previousChar = currentChar;
 
1214
 
 
1215
        if (!isWhiteSpace(currentChar))
 
1216
        {
 
1217
                previousNonWSChar = currentChar;
 
1218
                if (!isInComment && !isInLineComment && !isInQuote
 
1219
                        && !isImmediatelyPostComment
 
1220
                        && !isImmediatelyPostLineComment
 
1221
                        && !isSequenceReached("/*")
 
1222
                        && !isSequenceReached("//"))
 
1223
                        previousCommandChar = previousNonWSChar;
 
1224
        }
 
1225
 
 
1226
        int currentLineLength = currentLine.length();
 
1227
 
 
1228
        if (charNum + 1 < currentLineLength
 
1229
                && (!isWhiteSpace(peekNextChar()) || isInComment || isInLineComment))
 
1230
        {
 
1231
                currentChar = currentLine[++charNum];
 
1232
 
 
1233
                if (shouldConvertTabs && currentChar == '\t')
 
1234
                        currentChar = ' ';
 
1235
 
 
1236
                return true;
 
1237
        }
 
1238
        else        // end of line has been reached
 
1239
        {
 
1240
                if (sourceIterator->hasMoreLines())
 
1241
                {
 
1242
                        currentLine = sourceIterator->nextLine();
 
1243
                        spacePadNum = 0;
 
1244
                        inLineNumber++;
 
1245
 
 
1246
                        if (currentLine.length() == 0)
 
1247
                        {
 
1248
                                currentLine = string(" ");        // a null is inserted if this is not done
 
1249
                        }
 
1250
 
 
1251
                        // unless reading in the first line of the file,
 
1252
                        // break a new line.
 
1253
                        if (!isVirgin)
 
1254
                                isInLineBreak = true;
 
1255
                        else
 
1256
                                isVirgin = false;
 
1257
 
 
1258
                        if (isInLineComment)
 
1259
                                isImmediatelyPostLineComment = true;
 
1260
                        isInLineComment = false;
 
1261
 
 
1262
                        // check if is in preprocessor before line trimming
 
1263
                        isImmediatelyPostPreprocessor = isInPreprocessor;
 
1264
                        if (previousNonWSChar != '\\')
 
1265
                                isInPreprocessor = false;
 
1266
 
 
1267
                        trimNewLine();
 
1268
                        currentChar = currentLine[charNum];
 
1269
 
 
1270
                        if (shouldConvertTabs && currentChar == '\t')
 
1271
                                currentChar = ' ';
 
1272
 
 
1273
                        return true;
 
1274
                }
 
1275
                else
 
1276
                {
 
1277
                        endOfCodeReached = true;
 
1278
                        return false;
 
1279
                }
 
1280
        }
 
1281
}
 
1282
 
 
1283
/**
 
1284
* jump over the leading white space in the current line,
 
1285
* IF the line does not begin a comment or is in a preprocessor definition.
 
1286
*/
 
1287
void ASFormatter::trimNewLine()
 
1288
{
 
1289
        int len = currentLine.length();
 
1290
        charNum = 0;
 
1291
 
 
1292
        if (isInComment || isInPreprocessor)
 
1293
                return;
 
1294
 
 
1295
        while (isWhiteSpace(currentLine[charNum]) && charNum + 1 < len)
 
1296
                ++charNum;
 
1297
 
 
1298
        doesLineStartComment = false;
 
1299
        if (isSequenceReached("/*"))
 
1300
        {
 
1301
                charNum = 0;
 
1302
                doesLineStartComment = true;
 
1303
        }
 
1304
}
 
1305
 
 
1306
/**
 
1307
 * append a character to the current formatted line.
 
1308
 * Unless disabled (via canBreakLine == false), first check if a
 
1309
 * line-break has been registered, and if so break the
 
1310
 * formatted line, and only then append the character into
 
1311
 * the next formatted line.
 
1312
 *
 
1313
 * @param ch               the character to append.
 
1314
 * @param canBreakLine     if true, a registered line-break
 
1315
 */
 
1316
void ASFormatter::appendChar(char ch, bool canBreakLine)
 
1317
{
 
1318
        if (canBreakLine && isInLineBreak)
 
1319
                breakLine();
 
1320
        formattedLine.append(1, ch);
 
1321
}
 
1322
 
 
1323
/**
 
1324
 * append a string sequence to the current formatted line.
 
1325
 * Unless disabled (via canBreakLine == false), first check if a
 
1326
 * line-break has been registered, and if so break the
 
1327
 * formatted line, and only then append the sequence into
 
1328
 * the next formatted line.
 
1329
 *
 
1330
 * @param sequence         the sequence to append.
 
1331
 * @param canBreakLine     if true, a registered line-break
 
1332
 */
 
1333
void ASFormatter::appendSequence(const string &sequence, bool canBreakLine)
 
1334
{
 
1335
        if (canBreakLine && isInLineBreak)
 
1336
                breakLine();
 
1337
        formattedLine.append(sequence);
 
1338
}
 
1339
 
 
1340
/**
 
1341
 * append a space to the current formattedline, UNLESS the
 
1342
 * last character is already a white-space character.
 
1343
 */
 
1344
void ASFormatter::appendSpacePad()
 
1345
{
 
1346
        int len = formattedLine.length();
 
1347
        if (len > 0 && !isWhiteSpace(formattedLine[len-1]))
 
1348
        {
 
1349
                formattedLine.append(1, ' ');
 
1350
                spacePadNum++;
 
1351
        }
 
1352
}
 
1353
 
 
1354
/**
 
1355
 * append a space to the current formattedline, UNLESS the
 
1356
 * next character is already a white-space character.
 
1357
 */
 
1358
void ASFormatter::appendSpaceAfter()
 
1359
{
 
1360
        int len = currentLine.length();
 
1361
        if (charNum + 1 < len && !isWhiteSpace(currentLine[charNum+1]))
 
1362
        {
 
1363
                formattedLine.append(1, ' ');
 
1364
                spacePadNum++;
 
1365
        }
 
1366
}
 
1367
 
 
1368
/**
 
1369
 * register a line break for the formatted line.
 
1370
 */
 
1371
void ASFormatter::breakLine()
 
1372
{
 
1373
        isLineReady = true;
 
1374
        isInLineBreak = false;
 
1375
        spacePadNum = 0;
 
1376
        formattedLineCommentNum = string::npos;
 
1377
 
 
1378
        // queue an empty line prepend request if one exists
 
1379
        prependEmptyLine = isPrependPostBlockEmptyLineRequested;
 
1380
 
 
1381
        readyFormattedLine =  formattedLine;
 
1382
        if (isAppendPostBlockEmptyLineRequested)
 
1383
        {
 
1384
                isAppendPostBlockEmptyLineRequested = false;
 
1385
                isPrependPostBlockEmptyLineRequested = true;
 
1386
        }
 
1387
        else
 
1388
        {
 
1389
                isPrependPostBlockEmptyLineRequested = false;
 
1390
        }
 
1391
 
 
1392
        formattedLine = "";
 
1393
}
 
1394
 
 
1395
/**
 
1396
 * check if the currently reached open-bracket (i.e. '{')
 
1397
 * opens a:
 
1398
 * - a definition type block (such as a class or namespace),
 
1399
 * - a command block (such as a method block)
 
1400
 * - a static array
 
1401
 * this method takes for granted that the current character
 
1402
 * is an opening bracket.
 
1403
 *
 
1404
 * @return    the type of the opened block.
 
1405
 */
 
1406
BracketType ASFormatter::getBracketType() const
 
1407
{
 
1408
        BracketType returnVal;
 
1409
 
 
1410
        if (foundPreDefinitionHeader)
 
1411
        {
 
1412
                returnVal = DEFINITION_TYPE;
 
1413
                if (foundNamespaceHeader)
 
1414
                        returnVal = (BracketType)(returnVal | NAMESPACE_TYPE);
 
1415
                else if (foundClassHeader)
 
1416
                        returnVal = (BracketType)(returnVal | CLASS_TYPE);
 
1417
        }
 
1418
        else
 
1419
        {
 
1420
                bool isCommandType = false;
 
1421
 
 
1422
                if (previousNonWSChar != '=')
 
1423
                        isCommandType = (foundPreCommandHeader
 
1424
                                         || (currentHeader != NULL && isNonParenHeader)
 
1425
                                         || (previousCommandChar == ')')
 
1426
                                         || (previousCommandChar == ':' && !foundQuestionMark)
 
1427
                                         || (previousCommandChar == ';')
 
1428
                                         || ((previousCommandChar == '{' ||  previousCommandChar == '}')
 
1429
                                             && isPreviousBracketBlockRelated));
 
1430
 
 
1431
                returnVal = (isCommandType ? COMMAND_TYPE : ARRAY_TYPE);
 
1432
        }
 
1433
 
 
1434
        if (isOneLineBlockReached())
 
1435
                returnVal = (BracketType)(returnVal | SINGLE_LINE_TYPE);
 
1436
 
 
1437
        TRbracket(returnVal);
 
1438
        return returnVal;
 
1439
}
 
1440
 
 
1441
/**
 
1442
 * check if the currently reached  '*' or '&' character is
 
1443
 * a pointer-or-reference symbol, or another operator.
 
1444
 * this method takes for granted that the current character
 
1445
 * is either a '*' or '&'.
 
1446
 *
 
1447
 * @return        whether current character is a reference-or-pointer
 
1448
 */
 
1449
bool ASFormatter::isPointerOrReference() const
 
1450
{
 
1451
        bool isPR;
 
1452
        isPR = (!isInPotentialCalculation
 
1453
                || IS_A(bracketTypeStack->back(), DEFINITION_TYPE)
 
1454
                || (!isLegalNameChar(previousNonWSChar)
 
1455
                    && previousNonWSChar != ')'
 
1456
                    && previousNonWSChar != ']')
 
1457
               );
 
1458
 
 
1459
        if (!isPR)
 
1460
        {
 
1461
                char nextChar = peekNextChar();
 
1462
                isPR |= (!isWhiteSpace(nextChar)
 
1463
                         && nextChar != '-'
 
1464
                         && nextChar != '('
 
1465
                         && nextChar != '['
 
1466
                         && !isLegalNameChar(nextChar));
 
1467
        }
 
1468
 
 
1469
        return isPR;
 
1470
}
 
1471
 
 
1472
 
 
1473
/**
 
1474
 * check if the currently reached '-' character is
 
1475
 * a unary minus
 
1476
 * this method takes for granted that the current character
 
1477
 * is a '-'.
 
1478
 *
 
1479
 * @return        whether the current '-' is a unary minus.
 
1480
 */
 
1481
bool ASFormatter::isUnaryMinus() const
 
1482
{
 
1483
        return ((previousOperator == &AS_RETURN || !isalnum(previousCommandChar))
 
1484
                && previousCommandChar != '.'
 
1485
                && previousCommandChar != ')'
 
1486
                && previousCommandChar != ']');
 
1487
}
 
1488
 
 
1489
 
 
1490
/**
 
1491
 * check if the currently reached '-' or '+' character is
 
1492
 * part of an exponent, i.e. 0.2E-5.
 
1493
 * this method takes for granted that the current character
 
1494
 * is a '-' or '+'.
 
1495
 *
 
1496
 * @return        whether the current '-' is in an exponent.
 
1497
 */
 
1498
bool ASFormatter::isInExponent() const
 
1499
{
 
1500
        int formattedLineLength = formattedLine.length();
 
1501
        if (formattedLineLength >= 2)
 
1502
        {
 
1503
                char prevPrevFormattedChar = formattedLine[formattedLineLength - 2];
 
1504
                char prevFormattedChar = formattedLine[formattedLineLength - 1];
 
1505
 
 
1506
                return ((prevFormattedChar == 'e' || prevFormattedChar == 'E')
 
1507
                        && (prevPrevFormattedChar == '.' || isdigit(prevPrevFormattedChar)));
 
1508
        }
 
1509
        else
 
1510
                return false;
 
1511
}
 
1512
 
 
1513
/**
 
1514
 * check if a one-line bracket has been reached,
 
1515
 * i.e. if the currently reached '{' character is closed
 
1516
 * with a complimentry '}' elsewhere on the current line,
 
1517
 *.
 
1518
 * @return        has a one-line bracket been reached?
 
1519
 */
 
1520
bool ASFormatter::isOneLineBlockReached() const
 
1521
{
 
1522
        bool isInComment = false;
 
1523
        bool isInQuote = false;
 
1524
        int bracketCount = 1;
 
1525
        int currentLineLength = currentLine.length();
 
1526
        char quoteChar = ' ';
 
1527
 
 
1528
        for (int i = charNum + 1; i < currentLineLength; ++i)
 
1529
        {
 
1530
                char ch = currentLine[i];
 
1531
 
 
1532
                if (isInComment)
 
1533
                {
 
1534
                        if (currentLine.compare(i, 2, "*/") == 0)
 
1535
                        {
 
1536
                                isInComment = false;
 
1537
                                ++i;
 
1538
                        }
 
1539
                        continue;
 
1540
                }
 
1541
 
 
1542
                if (ch == '\\')
 
1543
                {
 
1544
                        ++i;
 
1545
                        continue;
 
1546
                }
 
1547
 
 
1548
                if (isInQuote)
 
1549
                {
 
1550
                        if (ch == quoteChar)
 
1551
                                isInQuote = false;
 
1552
                        continue;
 
1553
                }
 
1554
 
 
1555
                if (ch == '"' || ch == '\'')
 
1556
                {
 
1557
                        isInQuote = true;
 
1558
                        quoteChar = ch;
 
1559
                        continue;
 
1560
                }
 
1561
 
 
1562
                if (currentLine.compare(i, 2, "//") == 0)
 
1563
                        break;
 
1564
 
 
1565
                if (currentLine.compare(i, 2, "/*") == 0)
 
1566
                {
 
1567
                        isInComment = true;
 
1568
                        ++i;
 
1569
                        continue;
 
1570
                }
 
1571
 
 
1572
                if (ch == '{')
 
1573
                        ++bracketCount;
 
1574
                else if (ch == '}')
 
1575
                        --bracketCount;
 
1576
 
 
1577
                if (bracketCount == 0)
 
1578
                        return true;
 
1579
        }
 
1580
 
 
1581
        return false;
 
1582
}
 
1583
 
 
1584
/**
 
1585
 * check if one of a set of headers has been reached in the
 
1586
 * current position of the current line.
 
1587
 *
 
1588
 * @return             a pointer to the found header. Or a NULL if no header has been reached.
 
1589
 * @param headers      a vector of headers.
 
1590
 * @param checkBoundry
 
1591
 */
 
1592
const string *ASFormatter::findHeader(const vector<const string*> &headers, bool checkBoundry)
 
1593
{
 
1594
        return ASBeautifier::findHeader(currentLine, charNum, headers, checkBoundry);
 
1595
}
 
1596
 
 
1597
/**
 
1598
 * check if a line begins with the specified character
 
1599
 * i.e. if the current line begins with a open bracket.
 
1600
 *
 
1601
 * @return        true or false
 
1602
 */
 
1603
bool ASFormatter::lineBeginsWith(char charToCheck) const
 
1604
{
 
1605
        bool beginsWith = false;
 
1606
        size_t i = currentLine.find_first_not_of(" \t");
 
1607
 
 
1608
        if (i != string::npos)
 
1609
                if (currentLine[i] == charToCheck && (int) i == charNum)
 
1610
                        beginsWith = true;
 
1611
 
 
1612
        return beginsWith;
 
1613
}
 
1614
 
 
1615
/**
 
1616
 * adjust comment position because of adding or deleting spaces
 
1617
 * the spaces are added or deleted to formattedLine
 
1618
 * spacePadNum contains the adjustment
 
1619
 */
 
1620
void ASFormatter::adjustComments(void)
 
1621
{
 
1622
        assert(spacePadNum != 0);
 
1623
        assert(currentLine.compare(charNum, 2, "//") == 0
 
1624
               || currentLine.compare(charNum, 2, "/*") == 0);
 
1625
 
 
1626
 
 
1627
        // block comment must be closed on this line with nothing after it
 
1628
        if (currentLine.compare(charNum, 2, "/*") == 0)
 
1629
        {
 
1630
                size_t endNum = currentLine.find("*/", charNum + 2);
 
1631
                if (endNum == string::npos)
 
1632
                        return;
 
1633
                if (currentLine.find_first_not_of(" \t", endNum + 2) != string::npos)
 
1634
                        return;
 
1635
        }
 
1636
 
 
1637
        size_t len = formattedLine.length();
 
1638
        // if spaces were removed, need to add spaces before the comment
 
1639
        if (spacePadNum < 0)
 
1640
        {
 
1641
                int adjust = -spacePadNum;          // make the number positive
 
1642
                if (formattedLine[len-1] != '\t')   // don't adjust if a tab
 
1643
                        formattedLine.append(adjust, ' ');
 
1644
//              else                                                            // comment out to avoid compiler warning
 
1645
//                      adjust = 0;
 
1646
//              TRcomment(adjust);                  // trace macro
 
1647
        }
 
1648
        // if spaces were added, need to delete spaces before the comment, if possible
 
1649
        else if (spacePadNum > 0)
 
1650
        {
 
1651
                int adjust = spacePadNum;
 
1652
                if (formattedLine.find_last_not_of(' ') < len - adjust - 1
 
1653
                        && formattedLine[len-1] != '\t')    // don't adjust a tab
 
1654
                        formattedLine.resize(len - adjust);
 
1655
                // the following are commented out to avoid a Borland compiler warning
 
1656
                //else
 
1657
                //    adjust = 0;
 
1658
                TRcomment(-adjust);                 // trace macro
 
1659
        }
 
1660
}
 
1661
 
 
1662
/**
 
1663
 * append the current bracket inside the end of line comments
 
1664
 * currentChar contains the bracket, it will be appended to formattedLine
 
1665
 * formattedLineCommentNum is the comment location on formattedLine
 
1666
 */
 
1667
void ASFormatter::appendCharInsideComments(void)
 
1668
{
 
1669
        if (formattedLineCommentNum == string::npos             // does the comment start on the previous line?
 
1670
                || isBeforeComment())                                   // does a comment follow on this line?
 
1671
        {
 
1672
                appendCurrentChar(true);                        // don't attach
 
1673
                return;
 
1674
        }
 
1675
        assert(formattedLine.compare(formattedLineCommentNum, 2, "//") == 0
 
1676
               || formattedLine.compare(formattedLineCommentNum, 2, "/*") == 0);
 
1677
 
 
1678
        // find the previous non space char
 
1679
        size_t end = formattedLineCommentNum;
 
1680
        size_t beg = formattedLine.find_last_not_of(" \t", end-1);
 
1681
        if (beg == string::npos)                                // is the previous line comment only?
 
1682
        {
 
1683
                appendCurrentChar(true);                        // don't attach
 
1684
                return;
 
1685
        }
 
1686
        beg++;
 
1687
 
 
1688
        // insert the bracket
 
1689
        if (end - beg < 3)                                              // is there room to insert?
 
1690
                formattedLine.insert(beg, 3-end+beg, ' ');
 
1691
        if (formattedLine[beg] == '\t')                 // don't pad with a tab
 
1692
                formattedLine.insert(beg, 1, ' ');
 
1693
        formattedLine[beg+1] = currentChar;
 
1694
}
 
1695
 
 
1696
/**
 
1697
 * add or remove space padding to operators
 
1698
 * currentChar contains the paren
 
1699
 * the operators and necessary padding will be appended to formattedLine
 
1700
 * the calling function should have a continue statement after calling this method
 
1701
 *
 
1702
 * @param *newOperator     the operator to be padded
 
1703
 */
 
1704
void ASFormatter::padOperators(const string *newOperator)
 
1705
{
 
1706
        assert (shouldPadOperators);
 
1707
        assert(newOperator != NULL);
 
1708
 
 
1709
        bool shouldPad = (newOperator != &AS_COLON_COLON
 
1710
                          && newOperator != &AS_PAREN_PAREN
 
1711
                          && newOperator != &AS_BLPAREN_BLPAREN
 
1712
                          && newOperator != &AS_PLUS_PLUS
 
1713
                          && newOperator != &AS_MINUS_MINUS
 
1714
                          && newOperator != &AS_NOT
 
1715
                          && newOperator != &AS_BIT_NOT
 
1716
                          && newOperator != &AS_ARROW
 
1717
                          && newOperator != &AS_OPERATOR
 
1718
                          && newOperator != &AS_RETURN
 
1719
                          && !(newOperator == &AS_MINUS && isInExponent())
 
1720
                          && !(newOperator == &AS_MINUS             // check for negative number
 
1721
                               && (previousNonWSChar == '(' 
 
1722
                                   || previousNonWSChar == '=' 
 
1723
                                   || previousNonWSChar == ',')) 
 
1724
                      && !(newOperator == &AS_PLUS && isInExponent())
 
1725
                      && previousOperator != &AS_OPERATOR
 
1726
                      && !((newOperator == &AS_MULT || newOperator == &AS_BIT_AND)
 
1727
                           && isPointerOrReference())
 
1728
                      && !(newOperator == &AS_MULT
 
1729
                           && (previousNonWSChar == '.'
 
1730
                               || previousNonWSChar == '>'))    // check for ->
 
1731
                      && !((isInTemplate || isCharImmediatelyPostTemplate)
 
1732
                           && (newOperator == &AS_LS || newOperator == &AS_GR))
 
1733
                     );
 
1734
        // pad before operator
 
1735
        if (shouldPad
 
1736
                && !isInBlParen
 
1737
                && !(newOperator == &AS_COLON && !foundQuestionMark)
 
1738
                && newOperator != &AS_SEMICOLON
 
1739
                && newOperator != &AS_COMMA)
 
1740
                appendSpacePad();
 
1741
        appendSequence(*newOperator);
 
1742
        goForward(newOperator->length() - 1);
 
1743
 
 
1744
        // since this block handles '()' and '[]',
 
1745
        // the parenStack must be updated here accordingly!
 
1746
        if (newOperator == &AS_PAREN_PAREN
 
1747
                || newOperator == &AS_BLPAREN_BLPAREN)
 
1748
                parenStack->back()--;
 
1749
 
 
1750
        currentChar = (*newOperator)[newOperator->length() - 1];
 
1751
        // pad after operator
 
1752
        // but do not pad after a '-' that is a unary-minus.
 
1753
        if (shouldPad
 
1754
                && !isInBlParen
 
1755
                && !isBeforeComment()
 
1756
                && !(newOperator == &AS_MINUS && isUnaryMinus())
 
1757
                && !(currentLine.compare(charNum + 1, 1,  ";") == 0)
 
1758
                && !(currentLine.compare(charNum + 1, 2, "::") == 0))
 
1759
                appendSpaceAfter();
 
1760
 
 
1761
        previousOperator = newOperator;
 
1762
        return;
 
1763
}
 
1764
 
 
1765
/**
 
1766
 * add or remove space padding to parens
 
1767
 * currentChar contains the paren
 
1768
 * the parens and necessary padding will be appended to formattedLine
 
1769
 * the calling function should have a continue statement after calling this method
 
1770
 */
 
1771
void ASFormatter::padParens(void)
 
1772
{
 
1773
        assert(shouldPadParensOutside || shouldPadParensInside || shouldUnPadParens);
 
1774
        assert (currentChar == '(' || currentChar == ')');
 
1775
 
 
1776
        if (currentChar == '(')
 
1777
        {
 
1778
                int spacesOutsideToDelete = formattedLine.length() - 1;
 
1779
                int spacesInsideToDelete = 0;
 
1780
 
 
1781
                // compute spaces outside the opening paren to delete
 
1782
                if (shouldUnPadParens)
 
1783
                {
 
1784
                        char lastChar = ' ';
 
1785
                        bool prevIsParenHeader = false;
 
1786
                        size_t i = formattedLine.find_last_not_of(" \t");
 
1787
                        if (i != string::npos)
 
1788
                        {
 
1789
                                size_t end = i;
 
1790
                                spacesOutsideToDelete -= i;
 
1791
                                lastChar = formattedLine[i];
 
1792
                                // was last word a paren header?
 
1793
                                int start;          // start of the previous word
 
1794
                                for (start = i; start > 0; start--)
 
1795
                                {
 
1796
                                        if (isLegalNameChar(formattedLine[start]) || formattedLine[start] == '*')
 
1797
                                                continue;
 
1798
                                        start++;
 
1799
                                        break;
 
1800
                                }
 
1801
                                string prevWord = formattedLine.substr(start, end-start+1);
 
1802
                                // if previous word is a header, it will be a paren header
 
1803
                                const string *prevWordH = ASBeautifier::findHeader(formattedLine, start, headers);
 
1804
                                if (prevWordH != NULL)
 
1805
                                {
 
1806
                                        prevIsParenHeader = true;
 
1807
                                        TRxtra(*prevWordH);         // trace macro
 
1808
                                }
 
1809
                                else if (prevWord == "return"   // don't unpad return statements
 
1810
                                         || prevWord == "*")     // don't unpad multiply or pointer
 
1811
                                {
 
1812
                                        prevIsParenHeader = true;
 
1813
                                        TRxtra(prevWord);           // trace macro
 
1814
                                }
 
1815
                                // don't unpad variables
 
1816
                                else if (prevWord == "bool"
 
1817
                                         || prevWord ==  "int"
 
1818
                                         || prevWord ==  "void"
 
1819
                                         || prevWord ==  "void*"
 
1820
                                         || (prevWord.length() >= 6     // check end of word for _t
 
1821
                                             && prevWord.compare(prevWord.length()-2, 2, "_t") == 0)
 
1822
                                         || prevWord ==  "BOOL"
 
1823
                                         || prevWord ==  "DWORD"
 
1824
                                         || prevWord ==  "HWND"
 
1825
                                         || prevWord ==  "INT"
 
1826
                                         || prevWord ==  "LPSTR"
 
1827
                                         || prevWord ==  "VOID"
 
1828
                                         || prevWord ==  "LPVOID"
 
1829
                                        )
 
1830
                                {
 
1831
                                        prevIsParenHeader = true;
 
1832
                                        TRxtra(prevWord);           // trace macro
 
1833
                                }
 
1834
                        }
 
1835
                        // do not unpad operators, but leave them if already padded
 
1836
                        if (shouldPadParensOutside || prevIsParenHeader)
 
1837
                                spacesOutsideToDelete--;
 
1838
                        else if (lastChar == '|'          // check for ||
 
1839
                                 || lastChar == '&'      // check for &&
 
1840
                                 || lastChar == ','
 
1841
                                 || (lastChar == '>' && !foundCastOperator)
 
1842
                                 || lastChar == '<'
 
1843
                                 || lastChar == '?'
 
1844
                                 || lastChar == ':'
 
1845
                                 || lastChar == ';'
 
1846
                                 || lastChar == '='
 
1847
                                 || lastChar == '+'
 
1848
                                 || lastChar == '-'
 
1849
                                 || (lastChar == '*' && isInPotentialCalculation)
 
1850
                                 || lastChar == '/'
 
1851
                                 || lastChar == '%')
 
1852
                                spacesOutsideToDelete--;
 
1853
 
 
1854
                        if (spacesOutsideToDelete > 0)
 
1855
                        {
 
1856
                                formattedLine.erase(i + 1, spacesOutsideToDelete);
 
1857
                                spacePadNum -= spacesOutsideToDelete;
 
1858
                        }
 
1859
                }
 
1860
 
 
1861
                // pad open paren outside
 
1862
                char peekedCharOutside = peekNextChar();
 
1863
                if (shouldPadParensOutside)
 
1864
                        if (!(currentChar == '(' && peekedCharOutside == ')'))
 
1865
                                appendSpacePad();
 
1866
 
 
1867
                appendCurrentChar();
 
1868
 
 
1869
                // unpad open paren inside
 
1870
                if (shouldUnPadParens)
 
1871
                {
 
1872
                        size_t j = currentLine.find_first_not_of(" \t", charNum + 1);
 
1873
                        if (j != string::npos)
 
1874
                                spacesInsideToDelete = j - charNum - 1;
 
1875
                        if (shouldPadParensInside)
 
1876
                                spacesInsideToDelete--;
 
1877
                        if (spacesInsideToDelete > 0)
 
1878
                        {
 
1879
                                currentLine.erase(charNum + 1, spacesInsideToDelete);
 
1880
                                spacePadNum -= spacesInsideToDelete;
 
1881
                        }
 
1882
                }
 
1883
 
 
1884
                // pad open paren inside
 
1885
                char peekedCharInside = peekNextChar();
 
1886
                if (shouldPadParensInside)
 
1887
                        if (!(currentChar == '(' && peekedCharInside == ')'))
 
1888
                                appendSpaceAfter();
 
1889
 
 
1890
                TRunpad('(', spacesOutsideToDelete, spacesInsideToDelete);       // trace macro
 
1891
        }
 
1892
        else if (currentChar == ')' /*|| currentChar == ']'*/)
 
1893
        {
 
1894
                int spacesOutsideToDelete = 0;
 
1895
                int spacesInsideToDelete = formattedLine.length();
 
1896
 
 
1897
                // unpad close paren inside
 
1898
                if (shouldUnPadParens)
 
1899
                {
 
1900
                        size_t i = formattedLine.find_last_not_of(" \t");
 
1901
                        if (i != string::npos)
 
1902
                                spacesInsideToDelete = formattedLine.length() - 1 - i;
 
1903
                        if (shouldPadParensInside)
 
1904
                                spacesInsideToDelete--;
 
1905
                        if (spacesInsideToDelete > 0)
 
1906
                        {
 
1907
                                formattedLine.erase(i + 1, spacesInsideToDelete);
 
1908
                                spacePadNum -= spacesInsideToDelete;
 
1909
                        }
 
1910
                }
 
1911
 
 
1912
                // pad close paren inside
 
1913
                if (shouldPadParensInside)
 
1914
                        if (!(previousChar == '(' && currentChar == ')'))
 
1915
                                appendSpacePad();
 
1916
 
 
1917
                appendCurrentChar();
 
1918
 
 
1919
                // unpad close paren outside
 
1920
                if (shouldUnPadParens)
 
1921
                {
 
1922
                        // may have end of line comments
 
1923
                        size_t j = currentLine.find_first_not_of(" \t", charNum + 1);
 
1924
                        if (j != string::npos)
 
1925
                                if (currentLine[j] == '[' || currentLine[j] == ']')
 
1926
                                        spacesOutsideToDelete = j - charNum - 1;
 
1927
                        if (shouldPadParensOutside)
 
1928
                                spacesOutsideToDelete--;
 
1929
//                    spacesOutsideToDelete--;            // always leave 1 space
 
1930
 
 
1931
                        if (spacesOutsideToDelete > 0)
 
1932
                        {
 
1933
                                currentLine.erase(charNum + 1, spacesOutsideToDelete);
 
1934
                                spacePadNum -= spacesOutsideToDelete;
 
1935
                        }
 
1936
                }
 
1937
 
 
1938
                // pad close paren outside
 
1939
                char peekedCharOutside = peekNextChar();
 
1940
                if (shouldPadParensOutside)
 
1941
                        if (peekedCharOutside != ';'
 
1942
                                && peekedCharOutside != ','
 
1943
                                && peekedCharOutside != '.'
 
1944
                                && peekedCharOutside != '-')    // check for ->
 
1945
//                            && !(currentChar == ']' && peekedCharOutside == '['))
 
1946
                                appendSpaceAfter();
 
1947
 
 
1948
                TRunpad(')', spacesInsideToDelete, 0 /*spacesOutsideToDelete*/);       // trace macro
 
1949
        }
 
1950
        return;
 
1951
}
 
1952
 
 
1953
/**
 
1954
 * format brackets as attached or broken
 
1955
 * currentChar contains the bracket
 
1956
 * the brackets will be appended to the current formattedLine or a new formattedLine as necessary
 
1957
 * the calling function should have a continue statement after calling this method
 
1958
 *
 
1959
 * @param bracketType    the type of bracket to be formatted.
 
1960
 */
 
1961
void ASFormatter::formatBrackets(BracketType bracketType)
 
1962
{
 
1963
        assert(!IS_A(bracketType, ARRAY_TYPE));
 
1964
        assert (currentChar == '{' || currentChar == '}');
 
1965
 
 
1966
        if (currentChar == '{')
 
1967
        {
 
1968
                parenStack->push_back(0);
 
1969
        }
 
1970
        else if (currentChar == '}')
 
1971
        {
 
1972
                if (!parenStack->empty())
 
1973
                {
 
1974
                        parenStack->pop_back();
 
1975
                }
 
1976
        }
 
1977
 
 
1978
        if (currentChar == '{')
 
1979
        {
 
1980
                bool bdacBreak = false;
 
1981
                // should a Linux bracket be broken?
 
1982
                if (bracketFormatMode == BDAC_MODE)
 
1983
                {
 
1984
                        // always break a class
 
1985
                        if (IS_A((*bracketTypeStack)[bracketTypeStack->size()-1], CLASS_TYPE))
 
1986
                                bdacBreak = true;
 
1987
                        // break a namespace and the first bracket if a function
 
1988
                        else if (bracketTypeStack->size() <= 2)
 
1989
                        {
 
1990
                                if (IS_A((*bracketTypeStack)[bracketTypeStack->size()-1], NAMESPACE_TYPE)
 
1991
                                        || IS_A((*bracketTypeStack)[bracketTypeStack->size()-1], COMMAND_TYPE))
 
1992
                                        bdacBreak = true;
 
1993
                        }
 
1994
                        // break the first bracket after a namespace if a function
 
1995
                        else if (IS_A((*bracketTypeStack)[bracketTypeStack->size()-2], NAMESPACE_TYPE))
 
1996
                        {
 
1997
                                if (IS_A((*bracketTypeStack)[bracketTypeStack->size()-1], COMMAND_TYPE))
 
1998
                                        bdacBreak = true;
 
1999
                        }
 
2000
                        // if not C style then break the first bracket after a class if a function
 
2001
                        else if (!ASBeautifier::isCStyle)
 
2002
                        {
 
2003
                                if (IS_A((*bracketTypeStack)[bracketTypeStack->size()-2], CLASS_TYPE)
 
2004
                                        && IS_A((*bracketTypeStack)[bracketTypeStack->size()-1], COMMAND_TYPE))
 
2005
                                        bdacBreak = true;
 
2006
                        }
 
2007
                }
 
2008
                if (bracketFormatMode == ATTACH_MODE
 
2009
                        || (bracketFormatMode == BDAC_MODE && !bdacBreak))
 
2010
                {
 
2011
                        // are there comments before the bracket?
 
2012
                        if (isCharImmediatelyPostComment || isCharImmediatelyPostLineComment)
 
2013
                        {
 
2014
                                if ((shouldBreakOneLineBlocks || !IS_A(bracketType,  SINGLE_LINE_TYPE))
 
2015
                                        && peekNextChar() != '}')
 
2016
                                        appendCharInsideComments();
 
2017
                                else
 
2018
                                        appendCurrentChar(true);                // don't attach
 
2019
                        }
 
2020
                        else if (previousCommandChar == '{'
 
2021
                                 || previousCommandChar == '}'
 
2022
                                 || previousCommandChar == ';')  // '}' , ';' chars added for proper handling of '{' immediately after a '}' or ';'
 
2023
                        {
 
2024
                                appendCurrentChar(true);                        // don't attach
 
2025
                        }
 
2026
                        else
 
2027
                        {
 
2028
                                size_t firstChar = formattedLine.find_first_not_of(" \t");
 
2029
                                if (firstChar == string::npos)          // if a blank line preceeds this
 
2030
                                        appendCurrentChar(true);                // don't attach
 
2031
                                else if (shouldBreakOneLineBlocks
 
2032
                                         || !IS_A(bracketType,  SINGLE_LINE_TYPE)
 
2033
                                         || peekNextChar() == '}')
 
2034
                                {
 
2035
                                        appendSpacePad();
 
2036
                                        appendCurrentChar(false);               // OK to attach
 
2037
                                }
 
2038
                                else
 
2039
                                        appendCurrentChar(true);                // don't attach
 
2040
                        }
 
2041
                }
 
2042
                else if (bracketFormatMode == BREAK_MODE
 
2043
                         || (bracketFormatMode == BDAC_MODE && bdacBreak))
 
2044
                {
 
2045
                        if (isBeforeComment())
 
2046
                        {
 
2047
                                // do not break unless comment is at line end
 
2048
                                if (isBeforeLineEndComment(charNum))
 
2049
                                {
 
2050
                                        currentChar = ' ';                              // remove bracket from current line
 
2051
                                        appendOpeningBracket = true;    // append bracket to following line
 
2052
                                }
 
2053
                        }
 
2054
                        else if (!IS_A(bracketType,  SINGLE_LINE_TYPE))
 
2055
                                breakLine();
 
2056
                        else if (shouldBreakOneLineBlocks && peekNextChar() != '}')
 
2057
                                breakLine();
 
2058
 
 
2059
                        appendCurrentChar();
 
2060
                }
 
2061
                else if (bracketFormatMode == NONE_MODE)
 
2062
                {
 
2063
                        if (lineBeginsWith('{'))                // is opening bracket broken?
 
2064
                                appendCurrentChar(true);
 
2065
                        else
 
2066
                                appendCurrentChar(false);
 
2067
                }
 
2068
        }
 
2069
        else if (currentChar == '}')
 
2070
        {
 
2071
                // mark state of immediately after empty block
 
2072
                // this state will be used for locating brackets that appear immedately AFTER an empty block (e.g. '{} \n}').
 
2073
                if (previousCommandChar == '{')
 
2074
                        isImmediatelyPostEmptyBlock = true;
 
2075
 
 
2076
                if ((!(previousCommandChar == '{' && isPreviousBracketBlockRelated))            // this '{' does not close an empty block
 
2077
                        && (shouldBreakOneLineBlocks || !IS_A(bracketType,  SINGLE_LINE_TYPE))  // astyle is allowed to break on line blocks
 
2078
                        && (!(bracketFormatMode == NONE_MODE && IS_A(bracketType,  SINGLE_LINE_TYPE)))
 
2079
                        && !isImmediatelyPostEmptyBlock)                                        // this '}' does not immediately follow an empty block
 
2080
                {
 
2081
                        breakLine();
 
2082
                        appendCurrentChar();
 
2083
                }
 
2084
                else
 
2085
                {
 
2086
                        if (!isCharImmediatelyPostComment
 
2087
                                && !bracketFormatMode == NONE_MODE
 
2088
                                && !isImmediatelyPostEmptyBlock)
 
2089
                                isInLineBreak = false;
 
2090
 
 
2091
                        appendCurrentChar();
 
2092
 
 
2093
                        //if (!bracketFormatMode == NONE_MODE)
 
2094
                        //      if ((shouldBreakOneLineBlocks || !IS_A(bracketType,  SINGLE_LINE_TYPE))
 
2095
                        //              && !(currentChar == '}' && peekNextChar() == ';'))      // fixes }; placed on separate lines
 
2096
                        //              shouldBreakLineAfterComments = true;
 
2097
                }
 
2098
 
 
2099
                if (shouldBreakBlocks)
 
2100
                {
 
2101
                        isAppendPostBlockEmptyLineRequested = true;
 
2102
                }
 
2103
        }
 
2104
        return;
 
2105
}
 
2106
 
 
2107
/**
 
2108
 * format array brackets as attached or broken
 
2109
 * determine if the brackets can have an inStatement indent
 
2110
 * currentChar contains the bracket
 
2111
 * the brackets will be appended to the current formattedLine or a new formattedLine as necessary
 
2112
 * the calling function should have a continue statement after calling this method
 
2113
 *
 
2114
 * @param bracketType            the type of bracket to be formatted, must be an ARRAY_TYPE.
 
2115
 * @param isOpeningArrayBracket  indicates if this is the opening bracket for the array block.
 
2116
 */
 
2117
void ASFormatter::formatArrayBrackets(BracketType bracketType, bool isOpeningArrayBracket)
 
2118
{
 
2119
        assert(IS_A(bracketType, ARRAY_TYPE));
 
2120
        assert (currentChar == '{' || currentChar == '}');
 
2121
 
 
2122
        if (currentChar == '{')
 
2123
        {
 
2124
                // is this the first opening bracket in the array?
 
2125
                if (isOpeningArrayBracket)
 
2126
                {
 
2127
                        if (bracketFormatMode == ATTACH_MODE || bracketFormatMode == BDAC_MODE)
 
2128
                        {
 
2129
                                // don't attach to a preprocessor directive
 
2130
                                if (isImmediatelyPostPreprocessor)
 
2131
                                        appendCurrentChar(true);                        // don't attach
 
2132
                                // are there comments before the bracket?
 
2133
                                else if (isCharImmediatelyPostComment || isCharImmediatelyPostLineComment)
 
2134
                                {
 
2135
                                        appendCharInsideComments();
 
2136
                                }
 
2137
                                else
 
2138
                                {
 
2139
                                        // if bracket is broken or not an assignment
 
2140
                                        if (lineBeginsWith('{') || previousNonWSChar != '=')
 
2141
                                                appendSpacePad();
 
2142
                                        appendCurrentChar(false);                       // OK to attach
 
2143
                                }
 
2144
                        }
 
2145
                        else if (bracketFormatMode == BREAK_MODE)
 
2146
                        {
 
2147
                                if (isWhiteSpace(peekNextChar()))
 
2148
                                        breakLine();
 
2149
                                else if (isBeforeComment())
 
2150
                                {
 
2151
                                        // do not break unless comment is at line end
 
2152
                                        if (isBeforeLineEndComment(charNum))
 
2153
                                        {
 
2154
                                                currentChar = ' ';                              // remove bracket from current line
 
2155
                                                appendOpeningBracket = true;    // append bracket to following line
 
2156
                                        }
 
2157
                                }
 
2158
                                appendCurrentChar();
 
2159
                        }
 
2160
                        else if (bracketFormatMode == NONE_MODE)
 
2161
                        {
 
2162
                                if (lineBeginsWith('{'))                // is opening bracket broken?
 
2163
                                        appendCurrentChar();
 
2164
                                else
 
2165
                                        appendCurrentChar(false);
 
2166
                        }
 
2167
                }
 
2168
                else
 
2169
                        appendCurrentChar();     // not the first opening bracket - don't change
 
2170
 
 
2171
                // if an opening bracket ends the line there will be no inStatement indent
 
2172
                char nextChar = peekNextChar();
 
2173
                if (isWhiteSpace(nextChar)
 
2174
                        || isBeforeLineEndComment(charNum)
 
2175
                        || nextChar == '{')
 
2176
                        isNonInStatementArray = true;
 
2177
                if (isNonInStatementArray)
 
2178
                        TRarray('x');
 
2179
                else
 
2180
                        TRarray(' ');
 
2181
 
 
2182
        }
 
2183
        else if (currentChar == '}')
 
2184
        {
 
2185
                // does this close the first opening bracket in the array?
 
2186
                if (isOpeningArrayBracket && !IS_A(bracketType, SINGLE_LINE_TYPE) )
 
2187
                {
 
2188
                        breakLine();
 
2189
                        appendCurrentChar();
 
2190
                }
 
2191
                else
 
2192
                        appendCurrentChar();
 
2193
        }
 
2194
}
 
2195
 
 
2196
 
 
2197
}   // end namespace astyle