diff options
author | YamaArashi <shadow962@live.com> | 2016-01-24 03:44:21 -0800 |
---|---|---|
committer | YamaArashi <shadow962@live.com> | 2016-01-24 03:44:21 -0800 |
commit | 64814e13245d6439063a8eff85ac692394c673ee (patch) | |
tree | af6e43a2063d425b7c1e9bebd237c21b21d42d1f /tools/scaninc/scaninc.cpp | |
parent | aa3cafe9ba2bb30b273eec0bb3362ab17604a82e (diff) |
pokemon graphics data and makefile
Diffstat (limited to 'tools/scaninc/scaninc.cpp')
-rw-r--r-- | tools/scaninc/scaninc.cpp | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/tools/scaninc/scaninc.cpp b/tools/scaninc/scaninc.cpp new file mode 100644 index 000000000..9a228180a --- /dev/null +++ b/tools/scaninc/scaninc.cpp @@ -0,0 +1,320 @@ +// Copyright (c) 2015 YamaArashi + +#include <cstdio> +#include <cstdlib> +#include <stack> +#include <set> +#include <string> + +#ifdef _MSC_VER + +#define FATAL_INPUT_ERROR(format, ...) \ +do { \ + fprintf(stderr, "%s:%d " format, m_path.c_str(), m_lineNum, __VA_ARGS__); \ + exit(1); \ +} while (0) + +#define FATAL_ERROR(format, ...) \ +do { \ + fprintf(stderr, format, __VA_ARGS__); \ + exit(1); \ +} while (0) + +#else + +#define FATAL_INPUT_ERROR(format, ...) \ +do { \ + fprintf(stderr, "%s:%d " format, m_path.c_str(), m_lineNum, ##__VA_ARGS__); \ + exit(1); \ +} while (0) + +#define FATAL_ERROR(format, ...) \ +do { \ + fprintf(stderr, format, ##__VA_ARGS__); \ + exit(1); \ +} while (0) + +#endif // _MSC_VER + +#define SCANINC_MAX_PATH 255 + +enum class IncDirectiveType { + None, + Include, + Incbin +}; + +class AsmFile +{ +public: + AsmFile(std::string path); + ~AsmFile(); + IncDirectiveType ReadUntilIncDirective(std::string &path); + +private: + char *m_buffer; + int m_pos; + int m_size; + int m_lineNum; + std::string m_path; + + int GetChar() + { + if (m_pos >= m_size) + return -1; + + int c = m_buffer[m_pos++]; + + if (c == '\r') { + if (m_pos < m_size && m_buffer[m_pos++] == '\n') { + m_lineNum++; + return '\n'; + } else { + FATAL_INPUT_ERROR("CR line endings are not supported\n"); + } + } + + if (c == '\n') + m_lineNum++; + + return c; + } + + // No newline translation because it's not needed for any use of this function. + int PeekChar() + { + if (m_pos >= m_size) + return -1; + + return m_buffer[m_pos]; + } + + void SkipTabsAndSpaces() + { + while (m_pos < m_size && (m_buffer[m_pos] == '\t' || m_buffer[m_pos] == ' ')) + m_pos++; + } + + bool MatchIncDirective(std::string directiveName, std::string &path) + { + int length = directiveName.length(); + int i; + + for (i = 0; i < length && m_pos + i < m_size; i++) + if (directiveName[i] != m_buffer[m_pos + i]) + return false; + + if (i < length) + return false; + + m_pos += length; + + SkipTabsAndSpaces(); + + if (GetChar() != '"') + FATAL_INPUT_ERROR("no path after \".%s\" directive\n", directiveName.c_str()); + + path = ReadPath(); + + return true; + } + + std::string ReadPath(); + void SkipEndOfLineComment(); + void SkipMultiLineComment(); + void SkipString(); +}; + +AsmFile::AsmFile(std::string path) +{ + m_path = path; + + FILE *fp = fopen(path.c_str(), "rb"); + + if (fp == NULL) + FATAL_ERROR("Failed to open \"%s\" for reading.\n", path.c_str()); + + fseek(fp, 0, SEEK_END); + + m_size = ftell(fp); + + m_buffer = new char[m_size]; + + rewind(fp); + + if (fread(m_buffer, m_size, 1, fp) != 1) + FATAL_ERROR("Failed to read \"%s\".\n", path.c_str()); + + fclose(fp); + + m_pos = 0; + m_lineNum = 1; +} + +AsmFile::~AsmFile() +{ + delete[] m_buffer; +} + +IncDirectiveType AsmFile::ReadUntilIncDirective(std::string &path) +{ + // At the beginning of each loop iteration, the current file position + // should be at the start of a line or at the end of the file. + for (;;) { + SkipTabsAndSpaces(); + + IncDirectiveType incDirectiveType = IncDirectiveType::None; + + if (PeekChar() == '.') { + m_pos++; + + if (MatchIncDirective("incbin", path)) + incDirectiveType = IncDirectiveType::Incbin; + else if (MatchIncDirective("include", path)) + incDirectiveType = IncDirectiveType::Include; + } + + for (;;) { + int c = GetChar(); + + if (c == -1) + return incDirectiveType; + + if (c == ';') { + SkipEndOfLineComment(); + break; + } else if (c == '/' && PeekChar() == '*') { + m_pos++; + SkipMultiLineComment(); + } else if (c == '"') { + SkipString(); + } else if (c == '\n') { + break; + } + } + + if (incDirectiveType != IncDirectiveType::None) + return incDirectiveType; + } +} + +std::string AsmFile::ReadPath() +{ + int length = 0; + int startPos = m_pos; + + for (;;) { + int c = GetChar(); + + if (c == '"') + break; + + if (c == -1) + FATAL_INPUT_ERROR("unexpected EOF in include string\n"); + + if (c == 0) + FATAL_INPUT_ERROR("unexpected NUL character in include string\n"); + + if (c == '\n') + FATAL_INPUT_ERROR("unexpected end of line character in include string\n"); + + if (c == '\\') { + c = GetChar(); + + if (c != '"') + FATAL_INPUT_ERROR("unknown escape \"\\%c\" in include string\n", c); + } + + length++; + + if (length > SCANINC_MAX_PATH) + FATAL_INPUT_ERROR("path is too long"); + } + + return std::string(m_buffer, startPos, length); +} + +void AsmFile::SkipEndOfLineComment() +{ + int c; + + do { + c = GetChar(); + } while (c != -1 && c != '\n'); +} + +void AsmFile::SkipMultiLineComment() +{ + for (;;) { + int c = GetChar(); + + if (c == '*') { + if (PeekChar() == '/') { + m_pos++; + return; + } + } else if (c == -1) { + return; + } + } +} + +void AsmFile::SkipString() +{ + for (;;) { + int c = GetChar(); + + if (c == '"') + break; + + if (c == -1) + FATAL_INPUT_ERROR("unexpected EOF in string\n"); + + if (c == '\\') { + c = GetChar(); + } + } +} + +bool CanOpenFile(std::string path) +{ + FILE *fp = fopen(path.c_str(), "rb"); + + if (fp == NULL) + return false; + + fclose(fp); + return true; +} + +int main(int argc, char **argv) +{ + if (argc < 2) + FATAL_ERROR("Usage: scaninc ASM_FILE_PATH\n"); + + std::stack<std::string> filesToProcess; + std::set<std::string> dependencies; + + filesToProcess.push(std::string(argv[1])); + + while (!filesToProcess.empty()) { + AsmFile file(filesToProcess.top()); + + filesToProcess.pop(); + + IncDirectiveType incDirectiveType; + std::string path; + + while ((incDirectiveType = file.ReadUntilIncDirective(path)) != IncDirectiveType::None) { + bool inserted = dependencies.insert(path).second; + if (inserted + && incDirectiveType == IncDirectiveType::Include + && CanOpenFile(path)) + filesToProcess.push(path); + } + } + + for (const std::string &path : dependencies) { + printf("%s\n", path.c_str()); + } +} |