//
// aegis - project change supervisor
// Copyright (C) 2009, 2010, 2012, 2014 Peter Miller
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see .
//
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
validation_files_reserved::~validation_files_reserved()
{
}
validation_files_reserved::validation_files_reserved()
{
exceptions.push_back("__attribute__");
exceptions.push_back("__bool__");
exceptions.push_back("__bool");
exceptions.push_back("__DATE__");
exceptions.push_back("__FILE__");
exceptions.push_back("__func__");
exceptions.push_back("__FUNC__");
exceptions.push_back("__function__");
exceptions.push_back("__FUNCTION__");
exceptions.push_back("__inline__");
exceptions.push_back("__inline");
exceptions.push_back("__LINE__");
exceptions.push_back("__PRETTY_FUNCTION__");
exceptions.push_back("__TIME__");
exceptions.push_back("__TIMESTAMP__");
}
validation::pointer
validation_files_reserved::create(void)
{
return pointer(new validation_files_reserved());
}
bool
validation_files_reserved::check_branches()
const
{
return false;
}
bool
validation_files_reserved::check_downloaded()
const
{
return false;
}
bool
validation_files_reserved::check_foreign_copyright()
const
{
return false;
}
bool
validation_files_reserved::check_binaries()
const
{
return false;
}
bool
validation_files_reserved::is_a_reserved_word(const nstring &name)
const
{
#if 0
// These are just plain fugly.
if (name.size() >= 1 && (name[0] == '_' || name[name.size() - 1] == '_')
return true;
#endif
//
// The symbols defined by the standard (or in common use) are OK to
// be used. They aren't OK to be redefined, but that takes more
// semantic analysis, and this is just a heuristic.
//
if (exceptions.member(name))
return false;
//
// ANSI C++ Standard, Section 2.10, Paragraph 2:
// "Identifiers containing a double underscore (__) or beginning
// with an underscore and an upper-case letter are reserved for use
// by C++ implementations and standard libraries and shall not be
// used otherwise."
//
if (strstr(name.c_str(), "__"))
return true;
if (name.size() >= 2 && name[0] == '_' && isupper((unsigned char)name[1]))
return true;
//
// ANSI C Standard, Section 2.10, Paragraph 1:
// "In addition, some identifiers are reserved for use by C++
// implementations and standard libraries and shall not be used
// otherwise; no diagnostic is required."
//
//
// Can't find anything to complain about.
//
return false;
}
static nstring
get_character(const input::pointer &ip)
{
nstring_accumulator ac;
int c = ip->getch();
if (c < 0)
return ac.mkstr();
ac.push_back((char)c);
if (c != '\\')
return ac.mkstr();
c = ip->getch();
if (c < 0)
return ac.mkstr();
ac.push_back((char)c);
switch (c)
{
default:
return ac.mkstr();
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
for (;;)
{
c = ip->getch();
if (c < 0)
return ac.mkstr();
switch ((char)c)
{
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
continue;
default:
ip->ungetc((char)c);
return ac.mkstr();
}
}
case 'x':
case 'X':
for (;;)
{
c = ip->getch();
if (c < 0)
return ac.mkstr();
switch ((char)c)
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
continue;
default:
ip->ungetc((char)c);
return ac.mkstr();
}
}
}
}
bool
validation_files_reserved::check(change::pointer cp, fstate_src_ty *src)
{
nstring path(cp->file_path(src));
assert(!path.empty());
if (path.empty())
return true;
//
// figure out what sort of file we are looking at
//
nstring base = path.basename();
nstring lc_base = base.downcase();
bool isa_c_file = base.ends_with(".c");
bool isa_cxx_file =
base.ends_with(".C") ||
lc_base.ends_with(".c++") ||
lc_base.ends_with(".cc") ||
lc_base.ends_with(".cpp") ||
base.ends_with(".H") ||
lc_base.ends_with(".h++") ||
lc_base.ends_with(".hh") ||
lc_base.ends_with(".hpp")
;
bool isa_h_file = lc_base.ends_with(".h");
if (!isa_c_file && !isa_cxx_file && !isa_h_file)
return true;
os_become_orig();
bool ok = true;
input::pointer ip = input_file::open_text(path);
for (;;)
{
int ic = ip->getch();
if (ic < 0)
break;
unsigned char c = ic;
switch (c)
{
case ' ':
case '\b':
case '\f':
case '\n':
case '\r':
case '\t':
case '\v':
continue;
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
case 'V': case 'W': case 'X': case 'Y': case 'Z':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y': case 'z':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '$': case '_':
// Identifier (or pre-processor phase number)
{
nstring_accumulator ac;
for (;;)
{
ac.push_back(c);
ic = ip->getch();
if (ic < 0)
break;
c = ic;
switch (c)
{
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
case 's': case 't': case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '$': case '_':
continue;
default:
ip->ungetc(c);
break;
}
break;
}
nstring name = ac.mkstr();
if (is_a_reserved_word(name))
{
string_ty *text =
str_from_c
(
"identifier \"$name\" is reserved by the "
"ANSI C Standard"
);
sub_context_ty sc;
sc.var_set_long("Name", name);
string_ty *msg = sc.substitute(cp, text);
str_free(text);
ip->error(msg->str_text);
str_free(msg);
ok = false;
}
}
break;
case '/':
ic = ip->getch();
if (ic < 0)
break;
c = ic;
switch (c)
{
default:
ip->ungetc(c);
break;
case '/':
// This is a C++ comment
for (;;)
{
ic = ip->getch();
if (ic < 0)
break;
if (c == '\n')
break;
}
break;
case '*':
// This is a C comment
for (;;)
{
ic = ip->getch();
if (ic < 0)
break;
c = ic;
if (c != '*')
continue;
for (;;)
{
ic = ip->getch();
if (ic < 0)
break;
c = ic;
if (c != '*')
break;
}
if (c != '/')
continue;
break;
}
break;
}
break;
case '\'':
// Character constant
for (;;)
{
nstring ss = get_character(ip);
if (ss == "'")
break;
}
break;
case '"':
// String constant
for (;;)
{
nstring ss = get_character(ip);
if (ss == "\"")
break;
}
break;
}
}
ip.reset();
os_become_undo();
return ok;
}
// vim: set ts=8 sw=4 et :