in tools/nxstyle.c [1122:3489]
int main(int argc, char **argv, char **envp)
{
FILE *instream; /* File input stream */
char line[LINE_SIZE]; /* The current line being examined */
char buffer[100]; /* Localy format error strings */
char *lptr; /* Temporary pointer into line[] */
char *ext; /* Temporary file extension */
bool btabs; /* True: TAB characters found on the line */
bool bcrs; /* True: Carriage return found on the line */
bool bfunctions; /* True: In private or public functions */
bool bstatm; /* True: This line is beginning of a statement */
bool bfor; /* True: This line is beginning of a 'for' statement */
bool bif; /* True: This line is beginning of a 'if' statement */
bool bswitch; /* True: Within a switch statement */
bool bcase; /* True: Within a case statement of a switch */
bool bstring; /* True: Within a string */
bool bquote; /* True: Backslash quoted character next */
bool bblank; /* Used to verify block comment terminator */
bool bexternc; /* True: Within 'extern "C"' */
enum pptype_e ppline; /* > 0: The next line the continuation of a
* pre-processor command */
int rhcomment; /* Indentation of Comment to the right of code
* (-1 -> don't check position) */
int prevrhcmt; /* Indentation of previous Comment to the right
* of code (-1 -> don't check position) */
int lineno; /* Current line number */
int indent; /* Indentation level */
int ncomment; /* Comment nesting level on this line */
int prevncomment; /* Comment nesting level on the previous line */
int bnest; /* Brace nesting level on this line */
int prevbnest; /* Brace nesting level on the previous line */
int dnest; /* Data declaration nesting level on this line */
int prevdnest; /* Data declaration nesting level on the previous line */
int pnest; /* Parenthesis nesting level on this line */
int ppifnest; /* #if nesting level on this line */
int inasm; /* > 0: Within #ifdef __ASSEMBLY__ */
int comment_lineno; /* Line on which the last comment was closed */
int blank_lineno; /* Line number of the last blank line */
int noblank_lineno; /* A blank line is not needed after this line */
int lbrace_lineno; /* Line number of last left brace */
int rbrace_lineno; /* Last line containing a right brace */
int externc_lineno; /* Last line where 'extern "C"' declared */
int linelen; /* Length of the line */
int excess;
int n;
int i;
int c;
excess = 0;
while ((c = getopt(argc, argv, ":hv:gm:r:")) != -1)
{
switch (c)
{
case 'm':
excess = atoi(optarg);
if (excess < 1)
{
show_usage(argv[0], 1, "Bad value for <excess>.");
excess = 0;
}
break;
case 'v':
g_verbose = atoi(optarg);
if (g_verbose < 0 || g_verbose > 2)
{
show_usage(argv[0], 1, "Bad value for <level>.");
}
break;
case 'r':
g_rangestart[g_rangenumber] = atoi(strtok(optarg, ","));
g_rangecount[g_rangenumber++] = atoi(strtok(NULL, ","));
break;
case 'h':
show_usage(argv[0], 0, NULL);
break;
case ':':
show_usage(argv[0], 1, "Missing argument.");
break;
case '?':
show_usage(argv[0], 1, "Unrecognized option.");
break;
default:
show_usage(argv[0], 0, NULL);
break;
}
}
if (optind < argc - 1 || argv[optind] == NULL)
{
show_usage(argv[0], 1, "No file name given.");
}
/* Resolve the absolute path for the input file */
if (realpath(argv[optind], g_file_name) == NULL)
{
FATALFL("Failed to resolve absolute path.", g_file_name);
return 1;
}
/* Are we parsing a header file? */
ext = strrchr(g_file_name, '.');
if (ext == 0)
{
}
else if (strcmp(ext, ".h") == 0)
{
g_file_type = C_HEADER;
}
else if (strcmp(ext, ".c") == 0)
{
g_file_type = C_SOURCE;
}
if (g_file_type == UNKNOWN)
{
return 0;
}
if (white_file_list(g_file_name))
{
return 0;
}
instream = fopen(g_file_name, "r");
if (!instream)
{
FATALFL("Failed to open", g_file_name);
return 1;
}
/* Determine the line width */
g_maxline = get_line_width(instream) + excess;
rewind(instream);
btabs = false; /* True: TAB characters found on the line */
bcrs = false; /* True: Carriage return found on the line */
bfunctions = false; /* True: In private or public functions */
bswitch = false; /* True: Within a switch statement */
bcase = false; /* True: Within a case statement of a switch */
bstring = false; /* True: Within a string */
bexternc = false; /* True: Within 'extern "C"' */
bif = false; /* True: This line is beginning of a 'if' statement */
ppline = PPLINE_NONE; /* > 0: The next line the continuation of a
* pre-processor command */
rhcomment = 0; /* Indentation of Comment to the right of code
* (-1 -> don't check position) */
prevrhcmt = 0; /* Indentation of previous Comment to the right
* of code (-1 -> don't check position) */
lineno = 0; /* Current line number */
ncomment = 0; /* Comment nesting level on this line */
bnest = 0; /* Brace nesting level on this line */
dnest = 0; /* Data declaration nesting level on this line */
pnest = 0; /* Parenthesis nesting level on this line */
ppifnest = 0; /* #if nesting level on this line */
inasm = 0; /* > 0: Within #ifdef __ASSEMBLY__ */
comment_lineno = -1; /* Line on which the last comment was closed */
blank_lineno = -1; /* Line number of the last blank line */
noblank_lineno = -1; /* A blank line is not needed after this line */
lbrace_lineno = -1; /* Line number of last left brace */
rbrace_lineno = -1; /* Last line containing a right brace */
externc_lineno = -1; /* Last line where 'extern "C"' declared */
/* Process each line in the input stream */
while (fgets(line, LINE_SIZE, instream))
{
lineno++;
indent = 0;
prevbnest = bnest; /* Brace nesting level on the previous line */
prevdnest = dnest; /* Data declaration nesting level on the
* previous line */
prevncomment = ncomment; /* Comment nesting level on the previous line */
bstatm = false; /* True: This line is beginning of a
* statement */
bfor = false; /* REVISIT: Implies for() is all on one line */
/* If we are not in a comment, then this certainly is not a right-hand
* comment.
*/
prevrhcmt = rhcomment;
if (ncomment <= 0)
{
rhcomment = 0;
}
/* Check for a blank line */
for (n = 0; line[n] != '\n' && isspace((int)line[n]); n++)
{
}
if (line[n] == '\n')
{
if (n > 0)
{
ERROR("Blank line contains whitespace", lineno, 1);
}
if (lineno == 1)
{
ERROR("File begins with a blank line", 1, 1);
}
else if (lineno == blank_lineno + 1)
{
ERROR("Too many blank lines", lineno, 1);
}
else if (lineno == lbrace_lineno + 1)
{
ERROR("Blank line follows left brace", lineno, 1);
}
blank_lineno = lineno;
continue;
}
else /* This line is non-blank */
{
/* Check for a missing blank line after a comment */
if (lineno == comment_lineno + 1)
{
/* No blank line should be present if the current line contains
* a right brace, a pre-processor line, the start of another
* comment.
*
* REVISIT: Generates a false alarm if the current line is also
* a comment. Generally it is acceptable for one comment to
* follow another with no space separation.
*
* REVISIT: prevrhcmt is tested to case the preceding line
* contained comments to the right of the code. In such cases,
* the comments are normally aligned and do not follow normal
* indentation rules. However, this code will generate a false
* alarm if the comments are aligned to the right BUT the
* preceding line has no comment.
*/
if (line[n] != '}' && line[n] != '#' && prevrhcmt == 0)
{
ERROR("Missing blank line after comment", comment_lineno,
1);
}
}
/* Files must begin with a comment (the file header).
* REVISIT: Logically, this belongs in the STEP 2 operations
* below.
*/
if (lineno == 1 && (line[n] != '/' || line[n + 1] != '*'))
{
ERROR("Missing file header comment block", lineno, 1);
}
if (lineno == 2)
{
if (line[n] == '*' && line[n + 1] == '\n')
{
ERROR("Missing relative file path in file header", lineno,
n);
}
else if (isspace(line[n + 2]))
{
ERROR("Too many whitespaces before relative file path",
lineno, n);
}
else
{
const char *apps_dir = "apps/";
const size_t apps_len = strlen(apps_dir);
size_t offset;
#ifdef TOPDIR
/* TOPDIR macro contains the absolute path to the "nuttx"
* root directory. It should have been defined via Makefile
* and it is required to accurately evaluate the relative
* path contained in the file header. Otherwise, skip this
* verification.
*/
char *basedir = strstr(g_file_name, TOPDIR);
if (basedir != NULL)
{
/* Add 1 to the offset for the slash character */
offset = strlen(TOPDIR) + 1;
/* Duplicate the line from the beginning of the
* relative file path, removing the '\n' at the end of
* the string.
*/
char *line_dup = strndup(&line[n + 2],
strlen(&line[n + 2]) - 1);
if (strcmp(line_dup, basedir + offset) != 0)
{
ERROR("Relative file path does not match actual file",
lineno, n);
}
free(line_dup);
}
else if (strncmp(&line[n + 2], apps_dir, apps_len) != 0)
{
/* g_file_name neither belongs to "nuttx" repository
* nor begins with the root dir of the other
* repository (e.g. "apps/")
*/
ERROR("Path relative to repository other than \"nuttx\" "
"must begin with the root directory", lineno, n);
}
else
{
#endif
offset = 0;
if (strncmp(&line[n + 2], apps_dir, apps_len) == 0)
{
/* Input file belongs to the "apps" repository */
/* Calculate the offset to the first directory
* after the "apps/" folder.
*/
offset += apps_len;
}
/* Duplicate the line from the beginning of the
* relative file path, removing the '\n' at the end of
* the string.
*/
char *line_dup = strndup(&line[n + 2],
strlen(&line[n + 2]) - 1);
ssize_t base =
strlen(g_file_name) - strlen(&line_dup[offset]);
if (base < 0 ||
(base != 0 && g_file_name[base - 1] != '/') ||
strcmp(&g_file_name[base], &line_dup[offset]) != 0)
{
ERROR("Relative file path does not match actual file",
lineno, n);
}
free(line_dup);
#ifdef TOPDIR
}
#endif
}
}
/* Check for a blank line following a right brace */
if (bfunctions && lineno == rbrace_lineno + 1)
{
/* Check if this line contains a right brace. A right brace
* must be followed by 'else', 'while', 'break', a blank line,
* another right brace, or a pre-processor directive like #endif
*/
if (dnest == 0 &&
strchr(line, '}') == NULL && line[n] != '#' &&
strncmp(&line[n], "else", 4) != 0 &&
strncmp(&line[n], "while", 5) != 0 &&
strncmp(&line[n], "break", 5) != 0)
{
ERROR("Right brace must be followed by a blank line",
rbrace_lineno, n + 1);
}
/* If the right brace is followed by a pre-processor command
* like #endif (but not #else or #elif), then set the right
* brace line number to the line number of the pre-processor
* command (it then must be followed by a blank line)
*/
if (line[n] == '#')
{
int ii;
for (ii = n + 1; line[ii] != '\0' && isspace(line[ii]); ii++)
{
}
if (strncmp(&line[ii], "else", 4) != 0 &&
strncmp(&line[ii], "elif", 4) != 0)
{
rbrace_lineno = lineno;
}
}
}
}
/* STEP 1: Find the indentation level and the start of real stuff on
* the line.
*/
for (n = 0; line[n] != '\n' && isspace((int)line[n]); n++)
{
switch (line[n])
{
case ' ':
{
indent++;
}
break;
case '\t':
{
if (!btabs)
{
ERROR("TABs found. First detected", lineno, n);
btabs = true;
}
indent = (indent + 4) & ~3;
}
break;
case '\r':
{
if (!bcrs)
{
ERROR("Carriage returns found. "
"First detected", lineno, n);
bcrs = true;
}
}
break;
default:
{
snprintf(buffer, sizeof(buffer),
"Unexpected white space character %02x found",
line[n]);
ERROR(buffer, lineno, n);
}
break;
}
}
/* STEP 2: Detect some certain start of line conditions */
/* Skip over pre-processor lines (or continuations of pre-processor
* lines as indicated by ppline)
*/
if (line[indent] == '#' || ppline != PPLINE_NONE)
{
int len;
int ii;
/* Suppress error for comment following conditional compilation */
noblank_lineno = lineno;
/* Check pre-processor commands if this is not a continuation
* line.
*/
ii = indent + 1;
if (ppline == PPLINE_NONE)
{
/* Skip to the pre-processor command following the '#' */
while (line[ii] != '\0' && isspace(line[ii]))
{
ii++;
}
if (line[ii] != '\0')
{
/* Make sure that pre-processor definitions are all in
* the pre-processor definitions section.
*/
ppline = PPLINE_OTHER;
if (strncmp(&line[ii], "define", 6) == 0)
{
ppline = PPLINE_DEFINE;
if (g_section != PRE_PROCESSOR_DEFINITIONS)
{
/* A complication is the header files always have
* the idempotence guard definitions before the
* "Pre-processor Definitions section".
*/
if (g_section == NO_SECTION &&
g_file_type != C_HEADER)
{
/* Only a warning because there is some usage
* of define outside the Pre-processor
* Definitions section which is justifiable.
* Should be manually checked.
*/
WARN("#define outside of 'Pre-processor "
"Definitions' section",
lineno, ii);
}
}
}
/* Make sure that files are included only in the Included
* Files section.
*/
else if (strncmp(&line[ii], "include", 7) == 0)
{
if (g_section != INCLUDED_FILES)
{
/* Only a warning because there is some usage of
* include outside the Included Files section
* which may be is justifiable. Should be
* manually checked.
*/
WARN("#include outside of 'Included Files' "
"section",
lineno, ii);
}
else if (white_content_list(&line[ii], lineno))
{
g_skipmixedcase = true;
}
}
else if (strncmp(&line[ii], "if", 2) == 0)
{
ppifnest++;
ppline = PPLINE_IF;
ii += 2;
}
else if (strncmp(&line[ii], "elif", 4) == 0)
{
if (ppifnest == inasm)
{
inasm = 0;
}
ppline = PPLINE_ELIF;
ii += 4;
}
else if (strncmp(&line[ii], "else", 4) == 0)
{
if (ppifnest == inasm)
{
inasm = 0;
}
ppline = PPLINE_ELSE;
}
else if (strncmp(&line[ii], "endif", 4) == 0)
{
if (ppifnest == inasm)
{
inasm = 0;
}
ppifnest--;
ppline = PPLINE_ENDIF;
}
}
}
if (ppline == PPLINE_IF || ppline == PPLINE_ELIF)
{
int bdef = 0;
if (strncmp(&line[ii], "def", 3) == 0)
{
bdef = 1;
ii += 3;
}
else
{
while (line[ii] != '\0' && isspace(line[ii]))
{
ii++;
}
if (strncmp(&line[ii], "defined", 7) == 0)
{
bdef = 1;
ii += 7;
}
}
if (bdef)
{
while (line[ii] != '\0' &&
(isspace(line[ii]) || line[ii] == '('))
{
ii++;
}
if (strncmp(&line[ii], "__ASSEMBLY__", 12) == 0)
{
inasm = ppifnest;
}
}
}
/* Check if the next line will be a continuation of the pre-
* processor command.
*/
len = strlen(&line[indent]) + indent - 1;
if (line[len] == '\n')
{
len--;
}
/* Propagate rhcomment over preprocessor lines Issue #120 */
if (prevrhcmt != 0)
{
/* Don't check position */
rhcomment = -1;
}
lptr = strstr(line, "/*");
if (lptr != NULL)
{
n = lptr - &line[0];
if (line[n + 2] == '\n')
{
ERROR("C comment opening on separate line", lineno, n);
}
else if (!isspace((int)line[n + 2]) && line[n + 2] != '*')
{
ERROR("Missing space after opening C comment", lineno, n);
}
if (strstr(lptr, "*/") == NULL)
{
/* Increment the count of nested comments */
ncomment++;
}
if (ppline == PPLINE_DEFINE)
{
rhcomment = n;
if (prevrhcmt > 0 && n != prevrhcmt)
{
rhcomment = prevrhcmt;
WARN("Wrong column position of comment right of code",
lineno, n);
}
}
else
{
/* Signal rhcomment, but ignore position */
rhcomment = -1;
if (ncomment > 0 &&
(ppline == PPLINE_IF ||
ppline == PPLINE_ELSE ||
ppline == PPLINE_ELIF))
{
/* in #if... and #el... */
ERROR("No multiline comment right of code allowed here",
lineno, n);
}
}
}
if (line[len] != '\\' || ncomment > 0)
{
ppline = PPLINE_NONE;
}
continue;
}
/* Check for a single line comment */
linelen = strlen(line);
/* Minimum is slash, star, star, slash, newline */
if (linelen >= 5)
{
lptr = strstr(line, "*/");
if (line[indent] == '/' && line[indent + 1] == '*' &&
lptr - line == linelen - 3)
{
/* If preceding comments were to the right of code, then we can
* assume that there is a columnar alignment of columns that do
* no follow the usual alignment. So the rhcomment flag
* should propagate.
*/
rhcomment = prevrhcmt;
/* Check if there should be a blank line before the comment */
if (lineno > 1 &&
comment_lineno != lineno - 1 &&
blank_lineno != lineno - 1 &&
noblank_lineno != lineno - 1 &&
rhcomment == 0)
{
/* TODO: This generates a false alarm if preceded
* by a label.
*/
ERROR("Missing blank line before comment found", lineno, 1);
}
/* 'comment_lineno 'holds the line number of the last closing
* comment. It is used only to verify that the comment is
* followed by a blank line.
*/
comment_lineno = lineno;
}
}
/* Check for the comment block indicating the beginning of a new file
* section.
*/
if (check_section_header(line, lineno))
{
if (g_section == PRIVATE_FUNCTIONS || g_section == PUBLIC_FUNCTIONS)
{
bfunctions = true; /* Latched */
}
}
/* Check for some kind of declaration.
* REVISIT: The following logic fails for any non-standard types.
* REVISIT: Terminator after keyword might not be a space. Might be
* a newline, for example. struct and unions are often unnamed, for
* example.
*/
else if (inasm == 0)
{
if (strncmp(&line[indent], "auto ", 5) == 0 ||
strncmp(&line[indent], "bool ", 5) == 0 ||
strncmp(&line[indent], "char ", 5) == 0 ||
strncmp(&line[indent], "CODE ", 5) == 0 ||
strncmp(&line[indent], "const ", 6) == 0 ||
strncmp(&line[indent], "double ", 7) == 0 ||
strncmp(&line[indent], "struct ", 7) == 0 ||
strncmp(&line[indent], "struct\n", 7) == 0 || /* May be unnamed */
strncmp(&line[indent], "enum ", 5) == 0 ||
strncmp(&line[indent], "extern ", 7) == 0 ||
strncmp(&line[indent], "EXTERN ", 7) == 0 ||
strncmp(&line[indent], "FAR ", 4) == 0 ||
strncmp(&line[indent], "float ", 6) == 0 ||
strncmp(&line[indent], "int ", 4) == 0 ||
strncmp(&line[indent], "int16_t ", 8) == 0 ||
strncmp(&line[indent], "int32_t ", 8) == 0 ||
strncmp(&line[indent], "long ", 5) == 0 ||
strncmp(&line[indent], "off_t ", 6) == 0 ||
strncmp(&line[indent], "register ", 9) == 0 ||
strncmp(&line[indent], "short ", 6) == 0 ||
strncmp(&line[indent], "signed ", 7) == 0 ||
strncmp(&line[indent], "size_t ", 7) == 0 ||
strncmp(&line[indent], "ssize_t ", 8) == 0 ||
strncmp(&line[indent], "static ", 7) == 0 ||
strncmp(&line[indent], "time_t ", 7) == 0 ||
strncmp(&line[indent], "typedef ", 8) == 0 ||
strncmp(&line[indent], "uint8_t ", 8) == 0 ||
strncmp(&line[indent], "uint16_t ", 9) == 0 ||
strncmp(&line[indent], "uint32_t ", 9) == 0 ||
strncmp(&line[indent], "union ", 6) == 0 ||
strncmp(&line[indent], "union\n", 6) == 0 || /* May be unnamed */
strncmp(&line[indent], "unsigned ", 9) == 0 ||
strncmp(&line[indent], "void ", 5) == 0 ||
strncmp(&line[indent], "volatile ", 9) == 0)
{
/* Check if this is extern "C"; We don't typically indent
* following this.
*/
if (strncmp(&line[indent], "extern \"C\"", 10) == 0)
{
externc_lineno = lineno;
}
/* bfunctions: True: Processing private or public functions.
* bnest: Brace nesting level on this line
* dnest: Data declaration nesting level on this line
*/
/* REVISIT: Also picks up function return types */
/* REVISIT: Logic problem for nested data/function declarations */
if ((!bfunctions || bnest > 0) && dnest == 0)
{
dnest = 1;
}
/* Check for multiple definitions of variables on the line.
* Ignores declarations within parentheses which are probably
* formal parameters.
*/
if (pnest == 0)
{
int tmppnest;
bool tmpbstring;
/* Note, we have not yet parsed each character on the line so
* a comma have have been be preceded by '(' on the same line.
* We will have parse up to any comma to see if that is the
* case.
*/
for (i = indent, tmppnest = 0, tmpbstring = false;
line[i] != '\n' && line[i] != '\0';
i++)
{
if (tmppnest == 0 && !tmpbstring && line[i] == ',')
{
ERROR("Multiple data definitions", lineno, i + 1);
break;
}
else if (line[i] == '(')
{
tmppnest++;
}
else if (line[i] == ')')
{
if (tmppnest < 1)
{
/* We should catch this later */
break;
}
tmppnest--;
}
else if (line[i] == '"')
{
tmpbstring = !tmpbstring;
}
else if (line[i] == ';')
{
/* Break out if the semicolon terminates the
* declaration is found. Avoids processing any
* righthand comments in most cases.
*/
break;
}
}
}
}
/* Check for a keyword indicating the beginning of a statement.
* REVISIT: This, obviously, will not detect statements that do not
* begin with a C keyword (such as assignment statements).
*/
else if (strncmp(&line[indent], "break ", 6) == 0 ||
strncmp(&line[indent], "continue ", 9) == 0 ||
strncmp(&line[indent], "do ", 3) == 0 ||
strncmp(&line[indent], "else ", 5) == 0 ||
strncmp(&line[indent], "goto ", 5) == 0 ||
strncmp(&line[indent], "return ", 7) == 0 ||
strncmp(&line[indent], "while ", 6) == 0)
{
bstatm = true;
}
else if(strncmp(&line[indent], "if ", 3) == 0)
{
bif = true;
bstatm = true;
}
/* Spacing works a little differently for and switch statements */
else if (strncmp(&line[indent], "for ", 4) == 0)
{
bfor = true;
bstatm = true;
}
else if (strncmp(&line[indent], "switch ", 7) == 0)
{
bswitch = true;
}
else if (strncmp(&line[indent], "switch(", 7) == 0)
{
ERROR("Missing whitespace after keyword", lineno, n);
bswitch = true;
}
else if (strncmp(&line[indent], "case ", 5) == 0)
{
bcase = true;
}
else if (strncmp(&line[indent], "case(", 5) == 0)
{
ERROR("Missing whitespace after keyword", lineno, n);
bcase = true;
}
else if (strncmp(&line[indent], "default ", 8) == 0)
{
ERROR("Missing whitespace after keyword", lineno, n);
bcase = true;
}
else if (strncmp(&line[indent], "default:", 8) == 0)
{
bcase = true;
}
/* Also check for C keywords with missing white space */
else if (strncmp(&line[indent], "do(", 3) == 0 ||
strncmp(&line[indent], "while(", 6) == 0)
{
ERROR("Missing whitespace after keyword", lineno, n);
bstatm = true;
}
else if (strncmp(&line[indent], "if(", 3) == 0)
{
ERROR("Missing whitespace after keyword", lineno, n);
bif = true;
bstatm = true;
}
else if (strncmp(&line[indent], "for(", 4) == 0)
{
ERROR("Missing whitespace after keyword", lineno, n);
bfor = true;
bstatm = true;
}
}
/* STEP 3: Parse each character on the line */
bquote = false; /* True: Backslash quoted character next */
bblank = true; /* Used to verify block comment terminator */
for (; line[n] != '\n' && line[n] != '\0'; n++)
{
/* Report any use of non-standard white space characters */
if (isspace(line[n]))
{
if (line[n] == '\t')
{
if (!btabs)
{
ERROR("TABs found. First detected", lineno, n);
btabs = true;
}
}
else if (line[n] == '\r')
{
if (!bcrs)
{
ERROR("Carriage returns found. "
"First detected", lineno, n);
bcrs = true;
}
}
else if (line[n] != ' ')
{
snprintf(buffer, sizeof(buffer),
"Unexpected white space character %02x found",
line[n]);
ERROR(buffer, lineno, n);
}
}
/* Skip over identifiers */
if (ncomment == 0 && !bstring && (line[n] == '_' || isalpha(line[n])))
{
bool have_upper = false;
bool have_lower = false;
int ident_index = n;
/* Parse over the identifier. Check if it contains mixed upper-
* and lower-case characters.
*/
do
{
have_upper |= isupper(line[n]);
/* The coding standard provides for some exceptions of lower
* case characters in pre-processor strings:
*
* IPv[4|6] as an IP version number
* ICMPv6 as an ICMP version number
* IGMPv2 as an IGMP version number
* [0-9]p[0-9] as a decimal point
* d[0-9] as a divisor
* Hz for frequencies (including KHz, MHz, etc.)
*/
if (!have_lower && islower(line[n]))
{
switch (line[n])
{
/* A sequence containing 'v' may occur at the
* beginning of the identifier.
*/
case 'v':
if (n > 1 &&
line[n - 2] == 'I' &&
line[n - 1] == 'P' &&
(line[n + 1] == '4' ||
line[n + 1] == '6'))
{
}
else if (n > 3 &&
line[n - 4] == 'I' &&
line[n - 3] == 'C' &&
line[n - 2] == 'M' &&
line[n - 1] == 'P' &&
line[n + 1] == '6')
{
}
else if (n > 3 &&
line[n - 4] == 'I' &&
line[n - 3] == 'G' &&
line[n - 2] == 'M' &&
line[n - 1] == 'P' &&
line[n + 1] == '2')
{
}
else
{
have_lower = true;
}
break;
/* Sequences containing 'p', 'd', or 'z' must have
* been preceded by upper case characters.
*/
case 'p':
if (!have_upper || n < 1 ||
!isdigit(line[n - 1]) ||
!isdigit(line[n + 1]))
{
have_lower = true;
}
break;
case 'd':
if (!have_upper || !isdigit(line[n + 1]))
{
have_lower = true;
}
break;
case 'z':
if (!have_upper || n < 1 ||
line[n - 1] != 'H')
{
have_lower = true;
}
break;
break;
default:
have_lower = true;
break;
}
}
n++;
}
while (line[n] == '_' || isalnum(line[n]));
/* Check for mixed upper and lower case */
if (have_upper && have_lower)
{
/* Ignore symbols that begin with white-listed prefixes */
if (g_skipmixedcase ||
white_content_list(&line[ident_index], lineno))
{
/* No error */
}
/* Special case hex constants. These will look like
* identifiers starting with 'x' or 'X' but preceded
* with '0'
*/
else if (ident_index < 1 ||
(line[ident_index] != 'x' &&
line[ident_index] != 'X') ||
line[ident_index - 1] != '0')
{
ERROR("Mixed case identifier found",
lineno, ident_index);
}
else if (have_upper)
{
ERROR("Upper case hex constant found",
lineno, ident_index);
}
}
/* Check if the identifier is the last thing on the line */
if (line[n] == '\n' || line[n] == '\0')
{
break;
}
}
/* Handle comments */
if (line[n] == '/' && !bstring)
{
/* Check for start of a C comment */
if (line[n + 1] == '*')
{
if (line[n + 2] == '\n')
{
ERROR("C comment opening on separate line", lineno, n);
}
else if (!isspace((int)line[n + 2]) && line[n + 2] != '*')
{
ERROR("Missing space after opening C comment", lineno, n);
}
/* Increment the count of nested comments */
ncomment++;
/* If there is anything to the left of the left brace, then
* this must be a comment to the right of code.
* Also if preceding comments were to the right of code, then
* we can assume that there is a columnar alignment of columns
* that do no follow the usual alignment. So the rhcomment
* flag should propagate.
*/
if (prevrhcmt == 0)
{
if (n != indent)
{
rhcomment = n;
}
}
else
{
rhcomment = n;
if (prevrhcmt > 0 && n != prevrhcmt)
{
rhcomment = prevrhcmt;
if (n != indent)
{
WARN("Wrong column position of "
"comment right of code", lineno, n);
}
else
{
ERROR("Wrong column position or missing "
"blank line before comment", lineno, n);
}
}
}
/* Allow comments on the same line as the if statement */
if (bif == true)
{
bif = false;
}
n++;
continue;
}
/* Check for end of a C comment */
else if (n > 0 && line[n - 1] == '*')
{
if (n < 2)
{
ERROR("Closing C comment not indented", lineno, n);
}
else if (!isspace((int)line[n - 2]) && line[n - 2] != '*')
{
ERROR("Missing space before closing C comment", lineno,
n);
}
/* Check for block comments that are not on a separate line.
* This would be the case if we are we are within a comment
* that did not start on this line and the current line is
* not blank up to the point where the comment was closed.
*/
if (prevncomment > 0 && !bblank && rhcomment == 0)
{
ERROR("Block comment terminator must be on a "
"separate line", lineno, n);
}
#if 0
/* REVISIT: Generates false alarms when portions of an
* expression are commented out within the expression.
*/
if (line[n + 1] != '\n')
{
ERROR("Garbage on line after C comment", lineno, n);
}
#endif
/* Handle nested comments */
if (ncomment > 0)
{
/* Remember the line number of the line containing the
* closing of the outermost comment.
*/
if (--ncomment == 0)
{
/* 'comment_lineno 'holds the line number of the
* last closing comment. It is used only to
* verify that the comment is followed by a blank
* line.
*/
comment_lineno = lineno;
/* Note that rhcomment must persist to support a
* later test for comment alignment. We will fix
* that at the top of the loop when ncomment == 0.
*/
}
}
else
{
/* Note that rhcomment must persist to support a later
* test for comment alignment. We will will fix that
* at the top of the loop when ncomment == 0.
*/
ncomment = 0;
ERROR("Closing without opening comment", lineno, n);
}
n++;
continue;
}
/* Check for C++ style comments */
else if (line[n + 1] == '/')
{
/* Check for URI schemes, e.g. "http://" or "https://" */
if ((ncomment == 0) &&
(n == 0 || strncmp(&line[n - 1], "://", 3) != 0))
{
ERROR("C++ style comment", lineno, n);
n++;
continue;
}
}
}
/* Check if the line is blank so far. This is only used to
* to verify the the closing of a block comment is on a separate
* line. So we also need to treat '*' as a 'blank'.
*/
if (!isblank(line[n]) && line[n] != '*')
{
bblank = false;
}
/* Check for a string... ignore if we are in the middle of a
* comment.
*/
if (ncomment == 0)
{
/* Backslash quoted character */
if (line[n] == '\\')
{
bquote = true;
n++;
}
/* Check for quoted characters: \" in string */
if (line[n] == '"' && !bquote)
{
bstring = !bstring;
}
bquote = false;
}
/* The rest of the line is only examined of we are not in a comment,
* in a string or in assembly.
*
* REVISIT: Should still check for whitespace at the end of the
* line.
*/
if (ncomment == 0 && !bstring && inasm == 0)
{
switch (line[n])
{
/* Handle logic nested with curly braces */
case '{':
{
if (n > indent)
{
/* REVISIT: dnest is always > 0 here if bfunctions ==
* false.
*/
if (dnest == 0 || !bfunctions || lineno == rbrace_lineno)
{
ERROR("Left bracket not on separate line", lineno,
n);
}
}
else if (line[n + 1] != '\n')
{
if (dnest == 0)
{
ERROR("Garbage follows left bracket", lineno, n);
}
}
bnest++;
if (dnest > 0)
{
dnest++;
}
/* Check if we are within 'extern "C"', we don't
* normally indent in that case because the 'extern "C"'
* is conditioned on __cplusplus.
*/
if (lineno == externc_lineno ||
lineno - 1 == externc_lineno)
{
bexternc = true;
}
/* Suppress error for comment following a left brace */
noblank_lineno = lineno;
lbrace_lineno = lineno;
}
break;
case '}':
{
/* Decrement the brace nesting level */
if (bnest < 1)
{
ERROR("Unmatched right brace", lineno, n);
}
else
{
bnest--;
if (bnest < 1)
{
bnest = 0;
bswitch = false;
}
}
/* Decrement the declaration nesting level */
if (dnest < 3)
{
dnest = 0;
bexternc = false;
}
else
{
dnest--;
}
/* The right brace should be on a separate line */
if (n > indent)
{
if (dnest == 0)
{
ERROR("Right bracket not on separate line",
lineno, n);
}
}
/* Check for garbage following the left brace */
if (line[n + 1] != '\n' &&
line[n + 1] != ',' &&
line[n + 1] != ';')
{
int sndx = n + 1;
bool whitespace = false;
/* Skip over spaces */
while (line[sndx] == ' ')
{
sndx++;
}
/* One possibility is that the right bracket is
* followed by an identifier then a semi-colon.
* Comma is possible to but would be a case of
* multiple declaration of multiple instances.
*/
if (line[sndx] == '_' || isalpha(line[sndx]))
{
int endx = sndx;
/* Skip to the end of the identifier. Checking
* for mixed case identifiers will be done
* elsewhere.
*/
while (line[endx] == '_' ||
isalnum(line[endx]))
{
endx++;
}
/* Skip over spaces */
while (line[endx] == ' ')
{
whitespace = true;
endx++;
}
/* Handle according to what comes after the
* identifier.
*/
if (strncmp(&line[sndx], "while", 5) == 0)
{
ERROR("'while' must be on a separate line",
lineno, sndx);
}
else if (line[endx] == ',')
{
ERROR("Multiple data definitions on line",
lineno, endx);
}
else if (line[endx] == ';')
{
if (whitespace)
{
ERROR("Space precedes semi-colon",
lineno, endx);
}
}
else if (line[endx] == '=')
{
/* There's a struct initialization following */
check_spaces_leftright(line, lineno, endx, endx);
dnest = 1;
}
else
{
ERROR("Garbage follows right bracket",
lineno, n);
}
}
else
{
ERROR("Garbage follows right bracket", lineno, n);
}
}
/* The right brace should not be preceded with a a blank
* line.
*/
if (lineno == blank_lineno + 1)
{
ERROR("Blank line precedes right brace at line",
lineno, 1);
}
rbrace_lineno = lineno;
}
break;
/* Handle logic with parentheses */
case '(':
{
/* Increase the parenthetical nesting level */
pnest++;
/* Check for inappropriate space around parentheses */
if (line[n + 1] == ' ')
{
ERROR("Space follows left parenthesis", lineno, n);
}
}
break;
case ')':
{
/* Decrease the parenthetical nesting level */
if (pnest < 1)
{
ERROR("Unmatched right parentheses", lineno, n);
pnest = 0;
}
else
{
pnest--;
}
/* Allow ')' as first thing on the line (n == indent)
* Allow "for (xx; xx; )" (bfor == true)
*/
if (n > 0 && n != indent && line[n - 1] == ' ' && !bfor)
{
ERROR("Space precedes right parenthesis", lineno, n);
}
/* Unset bif if last parenthesis is closed */
if (bif == true && pnest == 0)
{
bif = false;
}
}
break;
/* Check for inappropriate space around square brackets */
case '[':
{
if (line[n + 1] == ' ')
{
ERROR("Space follows left bracket", lineno, n);
}
}
break;
case ']':
{
if (n > 0 && line[n - 1] == ' ')
{
ERROR("Space precedes right bracket", lineno, n);
}
}
break;
/* Semi-colon may terminate a declaration */
case ';':
{
if (!isspace((int)line[n + 1]))
{
ERROR("Missing whitespace after semicolon", lineno, n);
}
/* Semicolon terminates a declaration/definition if there
* was no left curly brace (i.e., dnest is only 1).
*/
if (dnest == 1)
{
dnest = 0;
}
}
break;
case ':':
{
if (bcase == true)
{
char *ndx = &line[n + 1];
while ((int)isspace(*ndx))
{
ndx++;
}
if (*ndx != '\0' && *ndx != '/')
{
ERROR("Case statement should be on a new line",
lineno, n);
}
bcase = false;
}
}
break;
case ',':
{
if (!isspace((int)line[n + 1]))
{
ERROR("Missing whitespace after comma", lineno, n);
}
}
break;
/* Skip over character constants */
case '\'':
{
int endndx = n + 2;
if (line[n + 1] != '\n' && line[n + 1] != '\0')
{
if (line[n + 1] == '\\')
{
for (;
line[endndx] != '\n' &&
line[endndx] != '\0' &&
line[endndx] != '\'';
endndx++);
}
n = endndx;
}
}
break;
/* Check for space around various operators */
case '-':
/* -> */
if (line[n + 1] == '>')
{
/* -> must have no whitespaces on its left or right */
check_nospaces_leftright(line, lineno, n, n + 1);
n++;
}
/* -- */
else if (line[n + 1] == '-')
{
/* "--" should be next to its operand. If there are
* whitespaces or non-operand characters on both left
* and right (e.g. "a -- ", "a[i --]", "(-- i)"),
* there's an error.
*/
check_operand_leftright(line, lineno, n, n + 1);
n++;
}
/* -= */
else if (line[n + 1] == '=')
{
check_spaces_leftright(line, lineno, n, n + 1);
n++;
}
/* Scientific notation with a negative exponent (eg. 10e-10)
* REVISIT: This fails for cases where the variable name
* ends with 'e' preceded by a digit:
* a = abc1e-10;
* a = ABC1E-10;
*/
else if ((line[n - 1] == 'e' || line[n - 1] == 'E') &&
isdigit(line[n + 1]) && isdigit(line[n - 2]))
{
n++;
}
else
{
/* '-' may function as a unary operator and snuggle
* on the left.
*/
check_spaces_left(line, lineno, n);
}
break;
case '+':
/* ++ */
if (line[n + 1] == '+')
{
/* "++" should be next to its operand. If there are
* whitespaces or non-operand characters on both left
* and right (e.g. "a ++ ", "a[i ++]", "(++ i)"),
* there's an error.
*/
check_operand_leftright(line, lineno, n, n + 1);
n++;
}
/* += */
else if (line[n + 1] == '=')
{
check_spaces_leftright(line, lineno, n, n + 1);
n++;
}
else
{
/* '+' may function as a unary operator and snuggle
* on the left.
*/
check_spaces_left(line, lineno, n);
}
break;
case '&':
/* &<variable> OR &(<expression>) */
if (isalpha((int)line[n + 1]) || line[n + 1] == '_' ||
line[n + 1] == '(')
{
}
/* &&, &= */
else if (line[n + 1] == '=' || line[n + 1] == '&')
{
check_spaces_leftright(line, lineno, n, n + 1);
n++;
}
else
{
check_spaces_leftright(line, lineno, n, n);
}
break;
case '/':
/* C comment terminator */
if (line[n - 1] == '*')
{
n++;
}
/* C++-style comment */
else if (line[n + 1] == '/')
{
/* Check for "http://" or "https://" */
if ((n < 5 || strncmp(&line[n - 5], "http://", 7) != 0) &&
(n < 6 || strncmp(&line[n - 6], "https://", 8) != 0))
{
ERROR("C++ style comment on at %d:%d\n",
lineno, n);
}
n++;
}
/* /= */
else if (line[n + 1] == '=')
{
check_spaces_leftright(line, lineno, n, n + 1);
n++;
}
/* Division operator */
else
{
check_spaces_leftright(line, lineno, n, n);
}
break;
case '*':
/* *\/, ** */
if (line[n] == '*' &&
(line[n + 1] == '/' ||
line[n + 1] == '*'))
{
n++;
break;
}
/* *<variable>, *(<expression>) */
else if (isalpha((int)line[n + 1]) ||
line[n + 1] == '_' ||
line[n + 1] == '(')
{
break;
}
/* (<type> *) */
else if (line[n + 1] == ')')
{
/* REVISIT: This gives false alarms on syntax like *--ptr */
if (line[n - 1] != ' ' && line[n - 1] != '(')
{
ERROR("Operator/assignment must be preceded "
"with whitespace", lineno, n);
}
break;
}
/* *= */
else if (line[n + 1] == '=')
{
check_spaces_leftright(line, lineno, n, n + 1);
n++;
}
else
{
/* A single '*' may be an binary operator, but
* it could also be a unary operator when used to deference
* a pointer.
*/
check_spaces_left(line, lineno, n);
}
break;
case '%':
/* %= */
if (line[n + 1] == '=')
{
check_spaces_leftright(line, lineno, n, n + 1);
n++;
}
else
{
check_spaces_leftright(line, lineno, n, n);
}
break;
case '<':
/* <=, <<, <<= */
if (line[n + 1] == '=')
{
check_spaces_leftright(line, lineno, n, n + 1);
n++;
}
else if (line[n + 1] == '<')
{
if (line[n + 2] == '=')
{
check_spaces_leftright(line, lineno, n, n + 2);
n += 2;
}
else
{
check_spaces_leftright(line, lineno, n, n + 1);
n++;
}
}
else
{
check_spaces_leftright(line, lineno, n, n);
}
break;
case '>':
/* >=, >>, >>= */
if (line[n + 1] == '=')
{
check_spaces_leftright(line, lineno, n, n + 1);
n++;
}
else if (line[n + 1] == '>')
{
if (line[n + 2] == '=')
{
check_spaces_leftright(line, lineno, n, n + 2);
n += 2;
}
else
{
check_spaces_leftright(line, lineno, n, n + 1);
n++;
}
}
else
{
check_spaces_leftright(line, lineno, n, n);
}
break;
case '|':
/* |=, || */
if (line[n + 1] == '=')
{
check_spaces_leftright(line, lineno, n, n + 1);
n++;
}
else if (line[n + 1] == '|')
{
check_spaces_leftright(line, lineno, n, n + 1);
n++;
}
else
{
check_spaces_leftright(line, lineno, n, n);
}
break;
case '^':
/* ^= */
if (line[n + 1] == '=')
{
check_spaces_leftright(line, lineno, n, n + 1);
n++;
}
else
{
check_spaces_leftright(line, lineno, n, n);
}
break;
case '=':
/* == */
if (line[n + 1] == '=')
{
check_spaces_leftright(line, lineno, n, n + 1);
n++;
}
else
{
check_spaces_leftright(line, lineno, n, n);
}
break;
case '~':
check_spaces_left(line, lineno, n);
break;
case '!':
/* != */
if (line[n + 1] == '=')
{
check_spaces_leftright(line, lineno, n, n + 1);
n++;
}
/* !! */
else if (line[n + 1] == '!')
{
check_spaces_left(line, lineno, n);
n++;
}
else
{
check_spaces_left(line, lineno, n);
}
break;
default:
break;
}
}
}
/* Loop terminates when NUL or newline character found */
if (line[n] == '\n' || line[n] == '\0')
{
/* If the parse terminated on the NULL, then back up to the last
* character (which should be the newline).
*/
int m = n;
if (line[m] == '\0' && m > 0)
{
m--;
}
/* Check for space at the end of the line. Except for carriage
* returns which we have already reported (one time) above.
*/
if (m > 1 && isspace((int)line[m - 1]) &&
line[m - 1] != '\n' && line[m - 1] != '\r')
{
/* Report warning on if statement only is pnest is 0
* This takes into consideration the multiline if statement.
*/
if (bif == true && pnest == 0)
{
WARN("If statement followed by garbage", lineno, n);
}
ERROR("Dangling whitespace at the end of line", lineno, m);
}
/* The line width is determined by the location of the final
* asterisk in block comments. The closing line of the block
* comment will exceed that by one one character, the '/'
* following the final asterisk.
*/
else if (m > g_maxline)
{
bool bslash;
int a;
for (bslash = false, a = m;
a > 2 && strchr("\n\r/", line[a]) != NULL;
a--)
{
if (line[a] == '/')
{
bslash = true;
}
}
if (bslash && line[a] == '*')
{
m = a + 1;
}
}
/* Check for long lines
*
* REVISIT: Long line checks suppressed on right hand comments
* for now. This just prevents a large number of difficult-to-
* fix complaints that we would have otherwise.
*/
if (m > g_maxline && !rhcomment)
{
/* Ignore the line 2 (file path) */
if (lineno == 2)
{
INFO("Skipping checking line 2: path file\n", 2, m);
}
else
{
ERROR("Long line found", lineno, m);
}
}
}
/* STEP 4: Check alignment */
/* Within a comment block, we need only check on the alignment of the
* comment.
*/
if ((ncomment > 0 || prevncomment > 0) && !bstring)
{
/* Nothing should begin in comment zero */
if (indent == 0 && line[0] != '/' && !bexternc)
{
/* NOTE: if this line contains a comment to the right of the
* code, then ncomment will be misleading because it was
* already incremented above.
*/
if (ncomment > 1 || rhcomment == 0)
{
ERROR("No indentation line", lineno, indent);
}
}
else if (indent == 1 && line[0] == ' ' && line[1] == '*')
{
/* Good indentation */
}
else if (indent > 0 && line[indent] == '\n')
{
ERROR("Whitespace on blank line", lineno, indent);
}
else if (indent > 0 && indent < 2)
{
if (bnest > 0)
{
ERROR("Insufficient indentation", lineno, indent);
}
else
{
ERROR("Expected indentation line", lineno, indent);
}
}
else if (indent > 0 && !bswitch)
{
if (line[indent] == '/')
{
/* Comments should like at offsets 2, 6, 10, ...
* This rule is not followed, however, if the comments are
* aligned to the right of the code.
*/
if ((indent & 3) != 2 && rhcomment == 0)
{
ERROR("Bad comment alignment", lineno, indent);
}
/* REVISIT: This screws up in cases where there is C code,
* followed by a comment that continues on the next line.
*/
else if (line[indent + 1] != '*')
{
ERROR("Missing asterisk in comment", lineno, indent);
}
}
else if (line[indent] == '*')
{
/* REVISIT: Generates false alarms on comments at the end of
* the line if there is nothing preceding (such as the aligned
* comments with a structure field definition). So disabled
* for comments before beginning of function definitions.
*
* Suppress this error if this is a comment to the right of
* code.
* Those may be unaligned.
*/
if ((indent & 3) != 3 && bfunctions && dnest == 0 &&
rhcomment == 0)
{
ERROR("Bad comment block alignment", lineno, indent);
}
if (line[indent + 1] != ' ' &&
line[indent + 1] != '*' &&
line[indent + 1] != '\n' &&
line[indent + 1] != '/')
{
ERROR("Invalid character after asterisk "
"in comment block", lineno, indent);
}
}
/* If this is not the line containing the comment start, then this
* line should begin with '*'
*/
else if (prevncomment > 0)
{
ERROR("Missing asterisk in comment block", lineno, indent);
}
}
}
/* Check for various alignment outside of the comment block */
else if ((ncomment == 0 && prevncomment == 0) && !bstring)
{
if (indent == 0 && strchr("\n#{}", line[0]) == NULL)
{
/* Ignore if we are at global scope */
if (prevbnest > 0)
{
bool blabel = false;
if (isalpha((int)line[indent]))
{
for (i = indent + 1; isalnum((int)line[i]) ||
line[i] == '_'; i++);
blabel = (line[i] == ':');
}
if (!blabel && !bexternc)
{
ERROR("No indentation line", lineno, indent);
}
}
}
else if (indent == 1 && line[0] == ' ' && line[1] == '*')
{
/* Good indentation */
}
else if (indent > 0 && line[indent] == '\n')
{
ERROR("Whitespace on blank line", lineno, indent);
}
else if (indent > 0 && indent < 2)
{
ERROR("Insufficient indentation line", lineno, indent);
}
else if (line[indent] == '{')
{
/* Check for left brace in first column, but preceded by a
* blank line. Should never happen (but could happen with
* internal compound statements).
*/
if (indent == 0 && lineno == blank_lineno + 1)
{
ERROR("Blank line before opening left brace", lineno, indent);
}
/* REVISIT: Possible false alarms in compound statements
* without a preceding conditional. That usage often violates
* the coding standard.
*/
else if (!bfunctions && (indent & 1) != 0)
{
ERROR("Bad left brace alignment", lineno, indent);
}
else if ((indent & 3) != 0 && !bswitch && dnest == 0)
{
ERROR("Bad left brace alignment", lineno, indent);
}
}
else if (line[indent] == '}')
{
/* REVISIT: Possible false alarms in compound statements
* without a preceding conditional. That usage often violates
* the coding standard.
*/
if (!bfunctions && (indent & 1) != 0)
{
ERROR("Bad left brace alignment", lineno, indent);
}
else if ((indent & 3) != 0 && !bswitch && prevdnest == 0)
{
ERROR("Bad right brace alignment", lineno, indent);
}
}
else if (indent > 0)
{
/* REVISIT: Generates false alarms when a statement continues on
* the next line. The bstatm check limits to lines beginning
* with C keywords.
* REVISIT: The bstatm check will not detect statements that
* do not begin with a C keyword (such as assignment statements).
* REVISIT: Generates false alarms on comments at the end of
* the line if there is nothing preceding (such as the aligned
* comments with a structure field definition). So disabled for
* comments before beginning of function definitions.
*/
if ((bstatm || /* Begins with C keyword */
(line[indent] == '/' &&
bfunctions &&
line[indent + 1] == '*')) && /* Comment in functions */
!bswitch && /* Not in a switch */
dnest == 0) /* Not a data definition */
{
if ((indent & 3) != 2)
{
ERROR("Bad alignment", lineno, indent);
}
}
/* Crazy cases. There should be no small odd alignments
* outside of comment/string. Odd alignments are possible
* on continued lines, but not if they are small.
*/
else if (indent == 1 || indent == 3)
{
ERROR("Small odd alignment", lineno, indent);
}
}
}
}
if (!bfunctions && g_file_type == C_SOURCE)
{
ERROR("\"Private/Public Functions\" not found!"
" File will not be checked", lineno, 1);
}
if (ncomment > 0 || bstring)
{
ERROR("Comment or string found at end of file", lineno, 1);
}
fclose(instream);
if (g_verbose == 1)
{
fprintf(stderr, "%s: %s nxstyle check\n", g_file_name,
g_status == 0 ? "PASSED" : "FAILED");
}
return g_status;
}