[mathicgb] 321/393: Added program for checking proper format of code files.

Doug Torrance dtorrance-guest at moszumanska.debian.org
Fri Apr 3 15:59:28 UTC 2015


This is an automated email from the git hooks/post-receive script.

dtorrance-guest pushed a commit to branch upstream
in repository mathicgb.

commit 6b201a7a02b9e7cef0b493232e44ffc006e0385a
Author: Bjarke Hammersholt Roune <bjarkehr.code at gmail.com>
Date:   Mon May 13 17:44:37 2013 +0200

    Added program for checking proper format of code files.
---
 .gitignore                      |   1 +
 src/checksource/CheckSource.cpp | 178 ++++++++++++++++++++++++++++
 src/checksource/Scanner.cpp     | 171 +++++++++++++++++++++++++++
 src/checksource/Scanner.hpp     | 255 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 605 insertions(+)

diff --git a/.gitignore b/.gitignore
index aa5a783..85ef426 100755
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,7 @@
 *.slo
 *.lo
 *.o
+*.exe
 
 # Compiled Dynamic libraries
 *.so
diff --git a/src/checksource/CheckSource.cpp b/src/checksource/CheckSource.cpp
new file mode 100755
index 0000000..94773c5
--- /dev/null
+++ b/src/checksource/CheckSource.cpp
@@ -0,0 +1,178 @@
+// Program for checking format of code, with respect to proper
+// copyright header, no tabs, order of includes and so on.
+//
+// This code is not pretty, especially not the duplication of Scanner,
+// but this makes this whole thing easy to compile and this is VERY
+// quick-and-dirty code anyway. Anyone who wants to clean up thing up
+// with proper integration into the build system is more than welcome
+// to do so.
+#include "Scanner.cpp"
+
+#include <iostream>
+#include <sstream>
+#include <stdexcept>
+#include <fstream>
+#include <string>
+
+void error(std::string str) {
+  throw std::runtime_error(str);
+}
+
+bool endsWith(const std::string& a, const std::string& b) {
+  return a.size() >= b.size() && a.substr(a.size() - b.size()) == b;
+}
+
+bool matchInclude(Scanner& in, bool& system) {
+  if (!in.match("#include "))
+    return false;
+
+  char delim = '\"';
+  system = false;
+  if (!in.match('\"')) {
+    if (in.match('<')) {
+      system = true;
+      delim = '>';
+    } else
+      in.reportError("Expected < or \" after #include.");
+  }
+
+  in.readUntil(delim);
+  in.expect(delim);
+  return true;
+}
+
+std::string stripEnding(const std::string& str) {
+  const auto index = str.find_last_of('.');
+  if (index == std::string::npos)
+    return str;
+  else
+    return str.substr(0, index);
+}
+
+
+
+void checkCopyrightHeader(Scanner& in) {
+  const char* const l1 = 
+    "// MathicGB copyright 2012 all rights reserved. "
+    "MathicGB comes with ABSOLUTELY\n";
+  const char* const l2 =
+    "// NO WARRANTY and is licensed as GPL v2.0 or later - see LICENSE.txt.\n";
+  in.match(l1);
+  in.match(l2);
+}
+
+void checkStdInc(Scanner& in) {
+  in.eatWhite();
+  in.expect("#include \"stdinc.h\"");
+}
+
+void checkIncludes(Scanner& in) {
+  bool sawSystem = false;
+  bool system;
+  while (matchInclude(in, system)) {
+    if (sawSystem && !system)
+      in.reportError("#include < > must come after all #include \" \".");
+    sawSystem = system;
+  }
+}
+
+void checkInclusionGuard(Scanner& in, const std::string& filename) {
+  auto normalize = [](const std::string& str) {
+    std::string norm;
+    for (size_t i = 0; i < str.size(); ++i)
+      if (str[i] != '_')
+        norm += std::toupper(str[i]);
+    return norm;
+  };
+
+  in.expect("#ifndef ");
+  const auto macroName = in.readString();
+  const auto fileNorm = normalize
+    ("MATHICGB_" + stripEnding(filename) + "_GUARD");
+
+  if (fileNorm != normalize(macroName)) {
+    std::ostringstream err;
+    err << "Inclusion guard name does not match file name.\n";
+    err << "Normalization removes _ and converts to upper case.\n";
+    err << "  Filename normalizes to: " << fileNorm << '\n';
+    err << "macro name normalizes to: " << normalize(macroName) << '\n';
+    in.reportError(err.str());
+  }
+
+  in.expect("#define ");
+  std::string macro2;
+  macro2 = in.readString();
+  if (macroName != macro2) {
+    std::ostringstream out;
+    out << "Inclusion guard #ifndef and #define macro name mismatch.\n";
+    out << "#ifndef macro name: " << macroName << '\n';
+    out << "#define macro name: " << macro2 << '\n';
+    in.reportError(out.str());
+  }
+}
+
+void checkOther(const std::string& filename) {
+  std::ifstream file(filename.c_str(), std::ios_base::binary);
+  Scanner in(file);
+  bool mgbNamespace = false;
+  while (!in.matchEOF()) {
+    if (in.peek() == '\r')
+      in.reportError("File contains dos/windows line ending character \\r.");
+    if (in.peek() == '\t')
+      in.reportError("File contains a tab.");
+    if (
+      in.match("Local Variables:") ||
+      in.match("compile-command:") ||
+      in.match("indent-tabs-mode:")
+    )
+      in.reportError("File contains emacs-specific command comments.");
+    if (in.match("namespace mgb") || in.match("MATHICGB_NAMESPACE_BEGIN"))
+      mgbNamespace = true;
+    else
+      in.get();
+  }
+  if (!mgbNamespace)
+    in.reportError("MATHICGB_NAMESPACE_BEGIN does not appear in file");
+}
+
+void checkFile(std::string filename) {
+  try {
+    std::cout << "Checking file " << filename << std::endl;
+    const bool hpp = endsWith(filename, ".hpp");
+    const bool cpp = endsWith(filename, ".cpp");
+    if (!hpp && !cpp)
+      return;
+
+    std::ifstream file(filename.c_str());
+    if (!file)
+      error("could not open file");
+    Scanner in(file);
+
+    if (in.peekWhite())
+      in.reportError
+        ("File should start with copyright header, not whitespace.");
+      
+    checkCopyrightHeader(in);
+    if (in.peekWhite())
+      in.reportError
+        ("There should not be whitespace after the copyright header.");
+
+    if (cpp)
+      checkStdInc(in);
+    else
+      checkInclusionGuard(in, filename);
+    checkIncludes(in);
+    file.close();
+
+    checkOther(filename);
+  } catch (std::exception& e) {
+    std::cout << "*** ERROR in file " << filename << " ***\n"
+      << e.what() << std::endl;
+  }
+}
+
+int main(int argc, char* argv[]) {
+  for (int i = 1; i < argc; ++i)
+    checkFile(argv[i]);
+  return 0;
+}
diff --git a/src/checksource/Scanner.cpp b/src/checksource/Scanner.cpp
new file mode 100755
index 0000000..9f8ec2b
--- /dev/null
+++ b/src/checksource/Scanner.cpp
@@ -0,0 +1,171 @@
+#include "Scanner.hpp"
+
+#include <limits>
+#include <sstream>
+#include <cstring>
+#include <stdexcept>
+
+static const size_t BufferSize = 10 * 1024;
+
+void reportSyntaxError(std::string s, uint64 lineNumber) {
+  std::ostringstream out;
+  out << "Syntax error on line " << lineNumber << ": " << s;
+  throw std::runtime_error(out.str());
+}
+
+void Scanner::reportError(std::string msg) const {
+  reportSyntaxError(msg, lineCount());
+}
+
+Scanner::Scanner(FILE* input):
+  mFile(input),
+  mStream(0),
+  mLineCount(1),
+  mChar(' '),
+  mBuffer(BufferSize),
+  mBufferPos(mBuffer.end())
+{
+  get();
+}
+
+Scanner::Scanner(std::istream& input):
+  mFile(0),
+  mStream(&input),
+  mLineCount(1),
+  mChar(' '),
+  mBuffer(BufferSize),
+  mBufferPos(mBuffer.end())
+{
+  get();
+}
+
+Scanner::Scanner(const char* const input):
+  mFile(0),
+  mStream(0),
+  mLineCount(1),
+  mChar(' '),
+  mBuffer(input, input + std::strlen(input)),
+  mBufferPos(mBuffer.begin())
+{
+  get();
+}
+
+Scanner::Scanner(const std::string& input):
+  mFile(0),
+  mStream(0),
+  mLineCount(1),
+  mChar(' '),
+  mBuffer(input.begin(), input.end()),
+  mBufferPos(mBuffer.begin())
+{
+  get();
+}
+
+bool Scanner::match(const char* const str) {
+  eatWhite();
+  const auto size = std::strlen(str);
+  if (!ensureBuffer(size))
+    return false;
+  if (size == 0)
+    return true;
+  if (peek() != *str)
+    return false;
+  if (std::strncmp(&*mBufferPos, str + 1, size - 1) != 0)
+    return false;
+  ignore(size);
+  return true;
+}
+
+bool Scanner::ensureBuffer(size_t min) {
+  const auto got = std::distance(mBufferPos, mBuffer.end()) + 1;
+  return got >= min || readBuffer(min - got);
+}
+
+void Scanner::expect(const char* str) {
+  eatWhite();
+
+  const char* it = str;
+  while (*it != '\0') {
+    int character = get();
+    if (*it == character) {
+      ++it;
+      continue;
+    }
+
+    // Read the rest of what is there to improve error message.
+    // TODO: read at least one char in total even if not alnum.
+    std::ostringstream got;
+    if (character == EOF && it == str)
+      got << "no more input";
+    else {
+      got << '\"' << std::string(str, it);
+      if (isalnum(character))
+        got << static_cast<char>(character);
+      while (isalnum(peek()))
+        got << static_cast<char>(get());
+      got << '\"';
+    }
+
+    reportErrorUnexpectedToken(str, got.str());
+  }
+}
+
+void Scanner::expectEOF() {
+  eatWhite();
+  if (get() != EOF)
+    reportErrorUnexpectedToken("no more input", "");
+}
+
+void Scanner::errorExpectTwo(char a, char b, int got) {
+  std::ostringstream err;
+  err << '\'' << a << "' or '" << b << '\'';
+  reportErrorUnexpectedToken(err.str(), got);
+}
+
+void Scanner::errorExpectOne(char expected, int got) {
+  std::ostringstream err;
+  err << '\'' << expected << '\'';
+  reportErrorUnexpectedToken(err.str(), got);
+}
+
+void Scanner::reportErrorUnexpectedToken(const std::string& expected, int got) {
+  std::ostringstream gotDescription;
+  if (got == EOF)
+    gotDescription << "no more input";
+  else
+    gotDescription << '\'' << static_cast<char>(got) << '\'';
+  reportErrorUnexpectedToken(expected, gotDescription.str());
+}
+
+void Scanner::reportErrorUnexpectedToken(
+  const std::string& expected,
+  const std::string& got
+) {
+  std::ostringstream errorMsg;
+  errorMsg << "Expected " << expected;
+  if (got != "")
+    errorMsg << ", but got " << got;
+  errorMsg << '.';
+  reportError(errorMsg.str());
+}
+
+bool Scanner::readBuffer(size_t minRead) {
+  auto saveCount = std::distance(mBufferPos, mBuffer.end());
+  if (mBufferPos != mBuffer.begin() && mBufferPos != mBuffer.end())
+    std::copy(mBufferPos, mBuffer.end(), mBuffer.begin());
+  mBuffer.resize(std::max(saveCount + minRead, mBuffer.capacity()));
+  auto readInto = reinterpret_cast<char*>(mBuffer.data() + saveCount);
+  auto readCount = mBuffer.size() - saveCount;
+
+  size_t didReadCount = 0;
+  if (mFile != 0) {
+    didReadCount = fread(readInto, 1, readCount, mFile);
+  } else if (mStream != 0) {
+    mStream->read(readInto, readCount);
+    didReadCount = mStream->gcount();
+  }
+  mBuffer.resize(saveCount + didReadCount);
+  mBufferPos = mBuffer.begin();
+
+  return didReadCount >= minRead;
+}
diff --git a/src/checksource/Scanner.hpp b/src/checksource/Scanner.hpp
new file mode 100755
index 0000000..c3c0076
--- /dev/null
+++ b/src/checksource/Scanner.hpp
@@ -0,0 +1,255 @@
+#ifndef MATHICGB_SCANNER_GUARD
+#define MATHICGB_SCANNER_GUARD
+
+#include <string>
+#include <cstdio>
+#include <vector>
+#include <type_traits>
+#include <limits>
+#include <sstream>
+#include <istream>
+
+typedef unsigned long long uint64;
+
+/// This class offers an input interface which is more convenient and
+/// often more efficient than dealing with a FILE* or std::istream
+/// directly. It keeps track of the current line number to report
+/// better error messages. Only one Scanner should be reading from a
+/// given FILE* or std::istream due to buffering and line number counting.
+///
+/// All input methods whose documentation does not specifically say
+/// otherwise skip whitespace.
+///
+/// There are four concepts for consuming input through a Scanner:
+///
+/// Read X: Require an X to be in the input, and return what is read.
+///
+/// Expect X: Require the exact value X to be in the input and skip past it.
+///
+/// Match X: Return true if the exact value X is in the input, and in that case
+///   skip past it. Otherwise return false and do nothing else.
+///
+/// MatchRead X: Return true of an X is in the input. In that case,
+///   read the X into a reference parameter and return true.
+///
+/// Peek X: Return true if X is the next thing int he input. Do not skip
+///   past anything. May or may not skip whitespace depending on what X is.
+///
+/// If a requirement is not met, Scanner reports a syntax error.
+class Scanner {
+public:
+  /// Construct a Scanner object reading from the input FILE*.
+  Scanner(FILE* input);
+
+  /// Construct a Scanner object reading from the input std::istream.
+  Scanner(std::istream& input);
+
+  /// Construct a Scanner object reading from the input string.
+  Scanner(const char* const input);
+
+  /// Construct a Scanner object reading from the input string.
+  Scanner(const std::string& input);
+
+  /// Reads a single character from the stream.
+  int get();
+
+  /// Takes count characters off the stream.
+  void ignore(size_t count);
+
+  /// Return true if the next character is c, and in that case skip
+  /// past it.
+  bool match(char c);
+
+  /// Return true if no more input.
+  bool matchEOF();
+
+  bool match(const char* const str);
+
+  /// Require the next character to be equal to expected. This
+  /// character is skipped past.
+  void expect(char expected);
+
+  /// Require the next character to be equal to a or b. This character
+  /// is skipped past.
+  void expect(char a, char b);
+
+  /// Require the following characters to be equal to str. These
+  /// characters are skipped past.
+  void expect(const char* str);
+
+  /// Require the following characters to be equal to str. These
+  /// characters are skipped past.
+  void expect(const std::string& str) {expect(str.c_str());}
+
+  /// Require that there is no more input.
+  void expectEOF();
+
+  /// Reads a T. T must be an integer type with a std::numeric_limits
+  /// specialization. Negative numbers are allows if T is signed.
+  template<class T>
+  T readInteger(bool negate = false);
+
+  /// Reads a T if it is there. Does not recognize + or - as the start
+  /// of an integer.
+  template<class T>
+  bool matchReadIntegerNoSign(T& t, bool negate = false);
+
+  void readUntil(char delimiter) {
+    while (peek() != delimiter && !matchEOF())
+      get();
+  }
+
+  std::string readString() {
+    std::string str;
+    while (!peekWhite() && !matchEOF())
+      str += get();
+    return str;
+  }
+
+  /// Returns the next character or EOF. Does not skip whitespace.
+  int peek() {return mChar;}
+
+  /// Returns true if the next character is a digit. Does not skip
+  /// whitespace.
+  bool peekDigit() {return std::isdigit(peek());}
+
+  bool peekAlpha() {return std::isalpha(peek());}
+
+  /// Returns true if the next character is whitespace. Does not skip
+  /// whitespace. Whitespace is defined by std::isspace().
+  bool peekWhite() {return isspace(peek());}
+
+  /// Returns true if the next character is + or -. Does not skip
+  /// whitespace.
+  bool peekSign() {return peek() == '+' || peek() == '-';}
+
+  /// Returns the number of newlines seen plus one. Does not skip
+  /// whitespace.
+  uint64 lineCount() const {return mLineCount;}
+
+  /// Reads past any whitespace.
+  inline void eatWhite();
+
+  void reportError(std::string msg) const;
+
+private:
+  void errorExpectTwo(char a, char b, int got);
+  void errorExpectOne(char expected, int got);
+
+  void reportErrorUnexpectedToken(const std::string& expected, int got);
+  void reportErrorUnexpectedToken
+    (const std::string& expected, const std::string& got);
+
+  bool ensureBuffer(size_t min);
+  bool readBuffer(size_t minRead);
+
+  FILE* mFile;
+  std::istream* mStream;
+  uint64 mLineCount;
+  int mChar; // next character on stream
+
+  std::vector<char> mBuffer;
+  std::vector<char>::iterator mBufferPos;
+};
+
+inline bool Scanner::matchEOF() {
+  eatWhite();
+  return peek() == EOF;
+}
+
+inline bool Scanner::match(char c) {
+  eatWhite();
+  if (c == peek()) {
+    get();
+    return true;
+  } else
+    return false;
+}
+
+inline void Scanner::expect(char a, char b) {
+  eatWhite();
+  int got = get();
+  if (got != a && got != b)
+    errorExpectTwo(a, b, got);
+}
+
+inline void Scanner::expect(char expected) {
+  eatWhite();
+  int got = get();
+  if (got != expected)
+    errorExpectOne(expected, got);
+}
+
+inline void Scanner::eatWhite() {
+  while (peekWhite())
+    get();
+}
+
+inline int Scanner::get() {
+  if (mChar == '\n')
+    ++mLineCount;
+  int oldChar = mChar;
+  if (mBufferPos == mBuffer.end() && !readBuffer(1))
+    mChar = EOF;
+  else {
+    mChar = *mBufferPos;
+    ++mBufferPos;
+  }
+  return oldChar;
+}
+
+inline void Scanner::ignore(size_t count) {
+  for (size_t i = 0; i < count; ++i)
+    get();
+}
+
+
+
+template<class T>
+T Scanner::readInteger(const bool negate) {
+  static_assert(std::numeric_limits<T>::is_integer, "");
+
+  eatWhite();
+  const bool minus = !match('+') && match('-');
+  const bool positive = minus == negate;
+  if (!peekDigit())
+    reportErrorUnexpectedToken("an integer", "");
+  // Skip leading zeroes and return if the number is zero.
+  if (peek() == '0') {
+    while (peek() == '0')
+      get();
+    if (!peekDigit())
+      return static_cast<T>(0);
+  }
+
+  // Checking this here allows us to recognize -0 as non-negative.
+  if (!positive && !std::numeric_limits<T>::is_signed)
+    reportErrorUnexpectedToken("a positive integer", "");
+
+  const auto min = std::numeric_limits<T>::min();
+  const auto max = std::numeric_limits<T>::max();
+  auto t = static_cast<T>(0);
+  while (peekDigit()) {
+    const auto c = static_cast<char>(get());
+    const auto d = positive ? c - '0' : -(c - '0');
+    if (positive ? t > (max - d) / 10 : t < (min - d) / 10) {
+      std::ostringstream err;
+      err << "an integer in the range [" << min
+          << ", " << max << ']';
+      reportErrorUnexpectedToken(err.str(), "");
+    }
+    t = t * 10 + d;
+  }
+  return t;
+}
+
+template<class T>
+bool Scanner::matchReadIntegerNoSign(T& t, bool negate) {
+  if (peekDigit()) {
+    t = readInteger<T>(negate);
+    return true;
+  } else
+    return false;
+}
+
+#endif

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/mathicgb.git



More information about the debian-science-commits mailing list