1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
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
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
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.
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.
26
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
29
// can trace only if NDEBUG is not defined
31
// #define TRACEswitch
38
//#define new DEBUG_NEW
45
#define TRswitch(a,b) *traceOut << lineNumber << a << b << endl;
47
#define TRswitch(a,b) ((void)0)
50
#define TRcase(a,b) *traceOut << lineNumber << a << b << endl;
52
#define TRcase(a,b) ((void)0)
55
#define TRmisc(a) *traceOut << lineNumber << a << endl;
57
#define TRmisc(a) ((void)0)
64
// ---------------------------- functions for ASEnhancer Class -------------------------------------
67
* ASEnhancer constructor
69
ASEnhancer::ASEnhancer()
71
// variables are initialized by init()
72
traceOut = new stringstream;
76
* Destructor of ASEnhancer
77
* Display the TRACE entries.
79
ASEnhancer::~ASEnhancer()
81
#if defined(TRACEswitch) || defined(TRACEcase) || defined(TRACEmisc)
83
string msg = "TRACE Entries\n\n";
87
while (getline(*traceOut, line))
92
sprintf(countLine, "\n%d Entries", count);
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);
106
* initialize the ASEnhancer.
108
* init() is called each time an ASFormatter object is initialized.
110
void ASEnhancer::init(int _indentLength,
111
string _indentString,
118
// formatting variables from ASFormatter and ASBeautifier
119
indentLength = _indentLength;
120
if (_indentString.compare(0, 1, "\t") == 0)
124
isCStyle = _isCStyle;
125
isJavaStyle = _isJavaStyle;
126
isSharpStyle = _isSharpStyle;
127
caseIndent = _caseIndent;
128
emptyLineFill = _emptyLineFill;
130
// unindent variables
136
lookingForCaseBracket = false;
137
unindentNextLine = false;
139
#if defined(TRACEswitch) || defined(TRACEcase) || defined(TRACEmisc)
140
*traceOut << "New file -------------" << endl;
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
151
* @param line the original formatted line will be updated if necessary.
153
void ASEnhancer::enhance(string &line)
155
static vector<switchVariables> swVector; // stack vector of switch variables
156
static switchVariables sw; // switch variables struct
158
static bool nextLineIsEventTable; // begin event table is reached
159
static bool isInEventTable; // need to indent an event table
161
bool isSpecialChar = false;
162
size_t lineLength; // length of the line being parsed
165
lineLength = line.length();
167
// check for beginning of event table
168
if (nextLineIsEventTable)
170
isInEventTable = true;
171
nextLineIsEventTable = false;
179
// test for unindent on attached brackets
180
if (unindentNextLine)
183
sw.unindentCase = true;
184
unindentNextLine = false;
185
TRcase(" unindent case ", sw.unindentDepth);
188
// parse characters in the current line.
190
for (size_t i = 0; i < lineLength; i++)
195
if (isWhiteSpaceX(ch))
198
// handle special characters (i.e. backslash+character such as \n, \t, ...)
201
isSpecialChar = false;
204
if (!(isInComment) && line.compare(i, 2, "\\\\") == 0)
209
if (!(isInComment) && ch == '\\')
211
isSpecialChar = true;
215
// handle quotes (such as 'x' and "Hello Dolly")
216
if (!(isInComment) && (ch == '"' || ch == '\''))
222
else if (quoteChar == ch)
233
if (!(isInComment) && line.compare(i, 2, "//") == 0)
235
// check for windows line markers
236
if (line.compare(i + 2, 1, "\xf0") > 0)
238
break; // finished with the line
240
else if (!(isInComment) && line.compare(i, 2, "/*") == 0)
246
else if ((isInComment) && line.compare(i, 2, "*/") == 0)
256
// if we have reached this far then we are NOT in a comment or string of special characters
258
if (line[i] == '{') // if open bracket
261
if (line[i] == '}') // if close bracket
264
// ---------------- process event tables --------------------------------------
266
// check for event table begin
267
if (findKeyword(line, i, "BEGIN_EVENT_TABLE")
268
|| findKeyword(line, i, "BEGIN_MESSAGE_MAP"))
269
nextLineIsEventTable = true;
271
// check for event table end
272
if (findKeyword(line, i, "END_EVENT_TABLE")
273
|| findKeyword(line, i, "END_MESSAGE_MAP"))
274
isInEventTable = false;
276
// ---------------- process switch statements ---------------------------------
278
if (findKeyword(line, i, "switch")) // if switch statement
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
289
// just want switch statements from this point
291
if (caseIndent || switchDepth == 0) // from here just want switch statements
292
continue; // get next char
294
if (line[i] == '{') // if open bracket
296
sw.switchBracketCount++;
297
if (lookingForCaseBracket) // if 1st after case statement
299
sw.unindentCase = true; // unindenting this case
300
sw.unindentDepth++; // bump depth
301
lookingForCaseBracket = false; // not looking now
302
TRcase(" unindent case ", sw.unindentDepth);
307
lookingForCaseBracket = false; // no opening bracket, don't indent
309
if (line[i] == '}') // if close bracket
311
sw.switchBracketCount--;
312
if (sw.switchBracketCount == 0) // if end of switch statement
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
322
// look for case or default header
324
if (findKeyword(line, i, "case") || findKeyword(line, i, "default"))
326
if (sw.unindentCase) // if unindented last case
328
sw.unindentCase = false; // stop unindenting previous case
329
sw.unindentDepth--; // reduce depth
331
for (; i < lineLength; i++) // bypass colon
334
if ((i + 1 < lineLength) && (line[i + 1] == ':'))
335
i++; // bypass scope resolution operator
340
for (; i < lineLength; i++) // bypass whitespace
342
if (!(isWhiteSpaceX(line[i])))
345
if (i < lineLength) // check for bracket
347
if (line[i] == '{') // if bracket found
349
sw.switchBracketCount++;
350
unindentNextLine = true; // start unindenting on next line
354
lookingForCaseBracket = true; // bracket must be on next line
355
i--; // need to check for comments
360
if (isInEventTable) // if need to indent
361
indentLine(line, 1); // do it
363
if (sw.unindentDepth > 0) // if need to unindent
364
unindentLine(line, sw.unindentDepth); // do it
368
* indent a line by a given number of tabsets
369
* by inserting leading whitespace to the line argument.
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.
375
int ASEnhancer::indentLine(string &line, const int indent) const
377
if (line.length() == 0
381
size_t charsToInsert; // number of chars to insert
383
if (useTabs) // if formatted with tabs
385
charsToInsert = indent; // tabs to insert
386
line.insert((size_t) 0, charsToInsert, '\t'); // insert the tabs
390
charsToInsert = indent * indentLength; // compute chars to insert
391
line.insert((size_t)0, charsToInsert, ' '); // insert the spaces
394
return charsToInsert;
398
* unindent a line by a given number of tabsets
399
* by erasing the leading whitespace from the line argument.
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.
405
int ASEnhancer::unindentLine(string &line, const int unindent) const
407
size_t whitespace = line.find_first_not_of(" \t");
409
if (whitespace == string::npos) // if line is blank
410
whitespace = line.length(); // must remove padding, if any
415
size_t charsToErase; // number of chars to erase
417
if (useTabs) // if formatted with tabs
419
charsToErase = unindent; // tabs to erase
420
if (charsToErase <= whitespace) // if there is enough whitespace
421
line.erase(0, charsToErase); // erase the tabs
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
438
* check if a specific line position contains a keyword.
440
* @return true if the word was found. false if the word was not found.
442
bool ASEnhancer::findKeyword(const string &line, int i, const char *keyword) const
444
if (line.compare(i, strlen(keyword), keyword) == 0)
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...)
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
455
if (wordEnd < lineLength)
457
endCh = line[wordEnd];
465
&& isLegalNameCharX(startCh)
466
&& isLegalNameCharX(prevCh))
470
else if (wordEnd >= lineLength
471
|| !isLegalNameCharX(startCh)
472
|| !isLegalNameCharX(endCh))
485
} // end namespace astyle