~ubuntu-branches/ubuntu/lucid/codelite/lucid

« back to all changes in this revision

Viewing changes to CodeFormatter/ASEnhancer.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Chow Loong Jin
  • Date: 2009-01-12 15:46:55 UTC
  • Revision ID: james.westby@ubuntu.com-20090112154655-sdynrljcb6u167yw
Tags: upstream-1.0.2674+dfsg
ImportĀ upstreamĀ versionĀ 1.0.2674+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
2
 *
 
3
 *   ASEnhancer.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
// can trace only if NDEBUG is not defined
 
30
#ifndef NDEBUG
 
31
// #define TRACEswitch
 
32
// #define TRACEcase
 
33
// #define TRACEmisc
 
34
#endif
 
35
 
 
36
#include "astyle.h"
 
37
 
 
38
//#define new DEBUG_NEW
 
39
 
 
40
#include <iostream>
 
41
#include <fstream>
 
42
#include <sstream>
 
43
 
 
44
#ifdef TRACEswitch
 
45
#define TRswitch(a,b)   *traceOut << lineNumber << a << b << endl;
 
46
#else
 
47
#define TRswitch(a,b)   ((void)0)
 
48
#endif // TRACEswitch
 
49
#ifdef TRACEcase
 
50
#define TRcase(a,b)     *traceOut << lineNumber << a << b << endl;
 
51
#else
 
52
#define TRcase(a,b)     ((void)0)
 
53
#endif // TRACEcase
 
54
#ifdef TRACEmisc
 
55
#define TRmisc(a)       *traceOut << lineNumber << a << endl;
 
56
#else
 
57
#define TRmisc(a)       ((void)0)
 
58
#endif // TRACEmisc
 
59
 
 
60
 
 
61
namespace astyle
 
62
{
 
63
 
 
64
// ---------------------------- functions for ASEnhancer Class -------------------------------------
 
65
 
 
66
/**
 
67
 * ASEnhancer constructor
 
68
 */
 
69
ASEnhancer::ASEnhancer()
 
70
{
 
71
        // variables are initialized by init()
 
72
        traceOut = new stringstream;
 
73
}
 
74
 
 
75
/**
 
76
 * Destructor of ASEnhancer
 
77
 * Display the TRACE entries.
 
78
 */
 
79
ASEnhancer::~ASEnhancer()
 
80
{
 
81
#if defined(TRACEswitch) || defined(TRACEcase) || defined(TRACEmisc)
 
82
        string line;
 
83
        string msg = "TRACE Entries\n\n";
 
84
        char countLine[50];
 
85
        int count = 0;
 
86
 
 
87
        while (getline(*traceOut, line))
 
88
        {
 
89
                msg += line + '\n';
 
90
                count++;
 
91
        }
 
92
        sprintf(countLine, "\n%d Entries", count);
 
93
        msg += countLine;
 
94
        // write a text file to "My Documents" (Windows)
 
95
        char filename [_MAX_PATH + _MAX_FNAME + _MAX_EXT + 1];   // full path and filename
 
96
        strcpy(filename, getenv("USERPROFILE"));
 
97
        strcat(filename, "\\My Documents\\tracee.txt");
 
98
        ofstream outfile(filename);
 
99
        outfile << msg;
 
100
        outfile.close();
 
101
#endif
 
102
        delete traceOut;
 
103
}
 
104
 
 
105
/**
 
106
 * initialize the ASEnhancer.
 
107
 *
 
108
 * init() is called each time an ASFormatter object is initialized.
 
109
 */
 
110
void ASEnhancer::init(int _indentLength,
 
111
                      string _indentString,
 
112
                      bool _isCStyle,
 
113
                      bool _isJavaStyle,
 
114
                      bool _isSharpStyle,
 
115
                      bool _caseIndent,
 
116
                      bool _emptyLineFill)
 
117
{
 
118
        // formatting variables from ASFormatter and ASBeautifier
 
119
        indentLength = _indentLength;
 
120
        if (_indentString.compare(0, 1, "\t") == 0)
 
121
                useTabs = true;
 
122
        else
 
123
                useTabs = false;
 
124
        isCStyle      = _isCStyle;
 
125
        isJavaStyle   = _isJavaStyle;
 
126
        isSharpStyle  = _isSharpStyle;
 
127
        caseIndent    = _caseIndent;
 
128
        emptyLineFill = _emptyLineFill;
 
129
 
 
130
        // unindent variables
 
131
        lineNumber = 0;
 
132
        bracketCount = 0;
 
133
        isInComment = false;
 
134
        isInQuote = false;
 
135
        switchDepth = 0;
 
136
        lookingForCaseBracket = false;
 
137
        unindentNextLine = false;
 
138
 
 
139
#if defined(TRACEswitch) || defined(TRACEcase) || defined(TRACEmisc)
 
140
        *traceOut << "New file -------------" << endl;
 
141
#endif
 
142
}
 
143
 
 
144
/**
 
145
 * additional formatting for line of source code.
 
146
 * every line of source code in a source code file should be sent
 
147
 *     one after the other to this function.
 
148
 * indents event tables
 
149
 * unindents the case blocks
 
150
 *
 
151
 * @param line       the original formatted line will be updated if necessary.
 
152
 */
 
153
void ASEnhancer::enhance(string &line)
 
154
{
 
155
        static vector<switchVariables>  swVector;       // stack vector of switch variables
 
156
        static switchVariables sw;                      // switch variables struct
 
157
 
 
158
        static bool nextLineIsEventTable;                               // begin event table is reached
 
159
        static bool isInEventTable;                                             // need to indent an event table
 
160
 
 
161
        bool   isSpecialChar = false;
 
162
        size_t  lineLength;                             // length of the line being parsed
 
163
 
 
164
        lineNumber++;
 
165
        lineLength = line.length();
 
166
 
 
167
        // check for beginning of event table
 
168
        if (nextLineIsEventTable)
 
169
        {
 
170
                isInEventTable = true;
 
171
                nextLineIsEventTable = false;
 
172
        }
 
173
 
 
174
        if (lineLength == 0
 
175
                && ! isInEventTable
 
176
                && ! emptyLineFill)
 
177
                return;
 
178
 
 
179
        // test for unindent on attached brackets
 
180
        if (unindentNextLine)
 
181
        {
 
182
                sw.unindentDepth++;
 
183
                sw.unindentCase = true;
 
184
                unindentNextLine = false;
 
185
                TRcase(" unindent case ", sw.unindentDepth);
 
186
        }
 
187
 
 
188
        // parse characters in the current line.
 
189
 
 
190
        for (size_t i = 0; i < lineLength; i++)
 
191
        {
 
192
                char ch = line[i];
 
193
 
 
194
                // bypass whitespace
 
195
                if (isWhiteSpaceX(ch))
 
196
                        continue;
 
197
 
 
198
                // handle special characters (i.e. backslash+character such as \n, \t, ...)
 
199
                if (isSpecialChar)
 
200
                {
 
201
                        isSpecialChar = false;
 
202
                        continue;
 
203
                }
 
204
                if (!(isInComment) && line.compare(i, 2, "\\\\") == 0)
 
205
                {
 
206
                        i++;
 
207
                        continue;
 
208
                }
 
209
                if (!(isInComment) && ch == '\\')
 
210
                {
 
211
                        isSpecialChar = true;
 
212
                        continue;
 
213
                }
 
214
 
 
215
                // handle quotes (such as 'x' and "Hello Dolly")
 
216
                if (!(isInComment) && (ch == '"' || ch == '\''))
 
217
                        if (!isInQuote)
 
218
                        {
 
219
                                quoteChar = ch;
 
220
                                isInQuote = true;
 
221
                        }
 
222
                        else if (quoteChar == ch)
 
223
                        {
 
224
                                isInQuote = false;
 
225
                                continue;
 
226
                        }
 
227
 
 
228
                if (isInQuote)
 
229
                        continue;
 
230
 
 
231
                // handle comments
 
232
 
 
233
                if (!(isInComment) && line.compare(i, 2, "//") == 0)
 
234
                {
 
235
                        // check for windows line markers
 
236
                        if (line.compare(i + 2, 1, "\xf0") > 0)
 
237
                                lineNumber--;
 
238
                        break;                 // finished with the line
 
239
                }
 
240
                else if (!(isInComment) && line.compare(i, 2, "/*") == 0)
 
241
                {
 
242
                        isInComment = true;
 
243
                        i++;
 
244
                        continue;
 
245
                }
 
246
                else if ((isInComment) && line.compare(i, 2, "*/") == 0)
 
247
                {
 
248
                        isInComment = false;
 
249
                        i++;
 
250
                        continue;
 
251
                }
 
252
 
 
253
                if (isInComment)
 
254
                        continue;
 
255
 
 
256
                // if we have reached this far then we are NOT in a comment or string of special characters
 
257
 
 
258
                if (line[i] == '{')                                 // if open bracket
 
259
                        bracketCount++;
 
260
 
 
261
                if (line[i] == '}')                     // if close bracket
 
262
                        bracketCount--;
 
263
 
 
264
                // ----------------  process event tables  --------------------------------------
 
265
 
 
266
                // check for event table begin
 
267
                if (findKeyword(line, i, "BEGIN_EVENT_TABLE")
 
268
                        || findKeyword(line, i, "BEGIN_MESSAGE_MAP"))
 
269
                        nextLineIsEventTable = true;
 
270
 
 
271
                // check for event table end
 
272
                if (findKeyword(line, i, "END_EVENT_TABLE")
 
273
                        || findKeyword(line, i, "END_MESSAGE_MAP"))
 
274
                        isInEventTable = false;
 
275
 
 
276
                // ----------------  process switch statements  ---------------------------------
 
277
 
 
278
                if (findKeyword(line, i, "switch"))                 // if switch statement
 
279
                {
 
280
                        switchDepth++;                                  // bump switch depth
 
281
                        TRswitch(" switch ", switchDepth);
 
282
                        swVector.push_back(sw);                         // save current variables
 
283
                        sw.switchBracketCount = 0;
 
284
                        sw.unindentCase = false;                        // don't clear case until end of switch
 
285
                        i += 5;                                         // bypass switch statement
 
286
                        continue;
 
287
                }
 
288
 
 
289
                // just want switch statements from this point
 
290
 
 
291
                if (caseIndent || switchDepth == 0)                 // from here just want switch statements
 
292
                        continue;                                      // get next char
 
293
 
 
294
                if (line[i] == '{')                                 // if open bracket
 
295
                {
 
296
                        sw.switchBracketCount++;
 
297
                        if (lookingForCaseBracket)                      // if 1st after case statement
 
298
                        {
 
299
                                sw.unindentCase = true;                     // unindenting this case
 
300
                                sw.unindentDepth++;                         // bump depth
 
301
                                lookingForCaseBracket = false;              // not looking now
 
302
                                TRcase(" unindent case ", sw.unindentDepth);
 
303
                        }
 
304
                        continue;
 
305
                }
 
306
 
 
307
                lookingForCaseBracket = false;                      // no opening bracket, don't indent
 
308
 
 
309
                if (line[i] == '}')                                 // if close bracket
 
310
                {
 
311
                        sw.switchBracketCount--;
 
312
                        if (sw.switchBracketCount == 0)                 // if end of switch statement
 
313
                        {
 
314
                                TRswitch("  endsw ", switchDepth);
 
315
                                switchDepth--;                              // one less switch
 
316
                                sw = swVector.back();                       // restore sw struct
 
317
                                swVector.pop_back();                        // remove last entry from stack
 
318
                        }
 
319
                        continue;
 
320
                }
 
321
 
 
322
                // look for case or default header
 
323
 
 
324
                if (findKeyword(line, i, "case") || findKeyword(line, i, "default"))
 
325
                {
 
326
                        if (sw.unindentCase)                            // if unindented last case
 
327
                        {
 
328
                                sw.unindentCase = false;                    // stop unindenting previous case
 
329
                                sw.unindentDepth--;                         // reduce depth
 
330
                        }
 
331
                        for (; i < lineLength; i++)                     // bypass colon
 
332
                        {
 
333
                                if (line[i] == ':')
 
334
                                        if ((i + 1 < lineLength) && (line[i + 1] == ':'))
 
335
                                                i++;                                                            // bypass scope resolution operator
 
336
                                        else
 
337
                                                break;
 
338
                        }
 
339
                        i++;
 
340
                        for (; i < lineLength; i++)                     // bypass whitespace
 
341
                        {
 
342
                                if (!(isWhiteSpaceX(line[i])))
 
343
                                        break;
 
344
                        }
 
345
                        if (i < lineLength)                             // check for bracket
 
346
                        {
 
347
                                if (line[i] == '{')                         // if bracket found
 
348
                                {
 
349
                                        sw.switchBracketCount++;
 
350
                                        unindentNextLine = true;                // start unindenting on next line
 
351
                                        continue;
 
352
                                }
 
353
                        }
 
354
                        lookingForCaseBracket = true;                   // bracket must be on next line
 
355
                        i--;                                            // need to check for comments
 
356
                        continue;
 
357
                }
 
358
        }   // end of for loop
 
359
 
 
360
        if (isInEventTable)                                                                     // if need to indent
 
361
                indentLine(line, 1);                                                    //    do it
 
362
 
 
363
        if (sw.unindentDepth > 0)                               // if need to unindent
 
364
                unindentLine(line, sw.unindentDepth);               //    do it
 
365
}
 
366
 
 
367
/**
 
368
 * indent a line by a given number of tabsets
 
369
 *    by inserting leading whitespace to the line argument.
 
370
 *
 
371
 * @param line          a pointer to the line to indent.
 
372
 * @param unindent      the number of tabsets to insert.
 
373
 * @return              the number of characters inserted.
 
374
 */
 
375
int ASEnhancer::indentLine(string  &line, const int indent) const
 
376
{
 
377
        if (line.length() == 0
 
378
                && ! emptyLineFill)
 
379
                return 0;
 
380
 
 
381
        size_t charsToInsert;                           // number of chars to insert
 
382
 
 
383
        if (useTabs)                                            // if formatted with tabs
 
384
        {
 
385
                charsToInsert = indent;                 // tabs to insert
 
386
                line.insert((size_t) 0, charsToInsert, '\t');    // insert the tabs
 
387
        }
 
388
        else
 
389
        {
 
390
                charsToInsert = indent * indentLength;  // compute chars to insert
 
391
                line.insert((size_t)0, charsToInsert, ' ');     // insert the spaces
 
392
        }
 
393
 
 
394
        return charsToInsert;
 
395
}
 
396
 
 
397
/**
 
398
 * unindent a line by a given number of tabsets
 
399
 *    by erasing the leading whitespace from the line argument.
 
400
 *
 
401
 * @param line          a pointer to the line to unindent.
 
402
 * @param unindent      the number of tabsets to erase.
 
403
 * @return              the number of characters erased.
 
404
 */
 
405
int ASEnhancer::unindentLine(string  &line, const int unindent) const
 
406
{
 
407
        size_t whitespace = line.find_first_not_of(" \t");
 
408
 
 
409
        if (whitespace == string::npos)         // if line is blank
 
410
                whitespace = line.length();         // must remove padding, if any
 
411
 
 
412
        if (whitespace == 0)
 
413
                return 0;
 
414
 
 
415
        size_t charsToErase;                    // number of chars to erase
 
416
 
 
417
        if (useTabs)                                    // if formatted with tabs
 
418
        {
 
419
                charsToErase = unindent;            // tabs to erase
 
420
                if (charsToErase <= whitespace)     // if there is enough whitespace
 
421
                        line.erase(0, charsToErase);    // erase the tabs
 
422
                else
 
423
                        charsToErase = 0;
 
424
        }
 
425
        else
 
426
        {
 
427
                charsToErase = unindent * indentLength; // compute chars to erase
 
428
                if (charsToErase <= whitespace)         // if there is enough whitespace
 
429
                        line.erase(0, charsToErase);        // erase the spaces
 
430
                else
 
431
                        charsToErase = 0;
 
432
        }
 
433
 
 
434
        return charsToErase;
 
435
}
 
436
 
 
437
/**
 
438
 * check if a specific line position contains a keyword.
 
439
 *
 
440
 * @return    true if the word was found. false if the word was not found.
 
441
 */
 
442
bool ASEnhancer::findKeyword(const string &line, int i, const char *keyword) const
 
443
{
 
444
        if (line.compare(i, strlen(keyword), keyword) == 0)
 
445
        {
 
446
                // check that this is a header and not a part of a longer word
 
447
                // (e.g. not at its begining, not at its middle...)
 
448
 
 
449
                int lineLength = line.length();
 
450
                int wordEnd = i + strlen(keyword);
 
451
                char startCh = keyword[0];      // first char of header
 
452
                char endCh = 0;                // char just after header
 
453
                char prevCh = 0;               // char just before header
 
454
 
 
455
                if (wordEnd < lineLength)
 
456
                {
 
457
                        endCh = line[wordEnd];
 
458
                }
 
459
                if (i > 0)
 
460
                {
 
461
                        prevCh = line[i-1];
 
462
                }
 
463
 
 
464
                if (prevCh != 0
 
465
                        && isLegalNameCharX(startCh)
 
466
                        && isLegalNameCharX(prevCh))
 
467
                {
 
468
                        return false;
 
469
                }
 
470
                else if (wordEnd >= lineLength
 
471
                         || !isLegalNameCharX(startCh)
 
472
                         || !isLegalNameCharX(endCh))
 
473
                {
 
474
                        return true;
 
475
                }
 
476
                else
 
477
                {
 
478
                        return false;
 
479
                }
 
480
        }
 
481
 
 
482
        return false;
 
483
}
 
484
 
 
485
}   // end namespace astyle