import from github
This commit is contained in:
1
tools/scaninc/.gitignore
vendored
Normal file
1
tools/scaninc/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
scaninc
|
19
tools/scaninc/LICENSE
Normal file
19
tools/scaninc/LICENSE
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2015 YamaArashi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
24
tools/scaninc/Makefile
Normal file
24
tools/scaninc/Makefile
Normal file
@ -0,0 +1,24 @@
|
||||
CXX ?= g++
|
||||
|
||||
CXXFLAGS = -Wall -Werror -std=c++11 -O2
|
||||
|
||||
SRCS = scaninc.cpp c_file.cpp asm_file.cpp source_file.cpp
|
||||
|
||||
HEADERS := scaninc.h asm_file.h c_file.h source_file.h
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
EXE := .exe
|
||||
else
|
||||
EXE :=
|
||||
endif
|
||||
|
||||
all: scaninc$(EXE)
|
||||
@:
|
||||
|
||||
scaninc$(EXE): $(SRCS) $(HEADERS)
|
||||
$(CXX) $(CXXFLAGS) $(SRCS) -o $@ $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
$(RM) scaninc scaninc.exe
|
192
tools/scaninc/asm_file.cpp
Normal file
192
tools/scaninc/asm_file.cpp
Normal file
@ -0,0 +1,192 @@
|
||||
// Copyright(c) 2015-2017 YamaArashi
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include "scaninc.h"
|
||||
#include "asm_file.h"
|
||||
|
||||
AsmFile::AsmFile(std::string path)
|
||||
{
|
||||
m_path = path;
|
||||
|
||||
FILE *fp = std::fopen(path.c_str(), "rb");
|
||||
|
||||
if (fp == NULL)
|
||||
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path.c_str());
|
||||
|
||||
std::fseek(fp, 0, SEEK_END);
|
||||
|
||||
m_size = std::ftell(fp);
|
||||
|
||||
m_buffer = new char[m_size];
|
||||
|
||||
std::rewind(fp);
|
||||
|
||||
if (std::fread(m_buffer, m_size, 1, fp) != 1)
|
||||
FATAL_ERROR("Failed to read \"%s\".\n", path.c_str());
|
||||
|
||||
std::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;
|
||||
|
||||
char c = PeekChar();
|
||||
if (c == '.' || c == '#')
|
||||
{
|
||||
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");
|
||||
|
||||
// Don't bother allowing any escape sequences.
|
||||
if (c == '\\')
|
||||
FATAL_INPUT_ERROR("unexpected escape in include string\n");
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
119
tools/scaninc/asm_file.h
Normal file
119
tools/scaninc/asm_file.h
Normal file
@ -0,0 +1,119 @@
|
||||
// Copyright(c) 2015-2017 YamaArashi
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef ASM_FILE_H
|
||||
#define ASM_FILE_H
|
||||
|
||||
#include <string>
|
||||
#include "scaninc.h"
|
||||
|
||||
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();
|
||||
};
|
||||
|
||||
#endif // ASM_FILE_H
|
307
tools/scaninc/c_file.cpp
Normal file
307
tools/scaninc/c_file.cpp
Normal file
@ -0,0 +1,307 @@
|
||||
// Copyright(c) 2017 YamaArashi
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#include "c_file.h"
|
||||
|
||||
CFile::CFile(std::string path)
|
||||
{
|
||||
m_path = path;
|
||||
|
||||
FILE *fp = std::fopen(path.c_str(), "rb");
|
||||
|
||||
if (fp == NULL)
|
||||
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path.c_str());
|
||||
|
||||
std::fseek(fp, 0, SEEK_END);
|
||||
|
||||
m_size = std::ftell(fp);
|
||||
|
||||
m_buffer = new char[m_size + 1];
|
||||
m_buffer[m_size] = 0;
|
||||
|
||||
std::rewind(fp);
|
||||
|
||||
if (std::fread(m_buffer, m_size, 1, fp) != 1)
|
||||
FATAL_ERROR("Failed to read \"%s\".\n", path.c_str());
|
||||
|
||||
std::fclose(fp);
|
||||
|
||||
m_pos = 0;
|
||||
m_lineNum = 1;
|
||||
}
|
||||
|
||||
CFile::~CFile()
|
||||
{
|
||||
delete[] m_buffer;
|
||||
}
|
||||
|
||||
void CFile::FindIncbins()
|
||||
{
|
||||
char stringChar = 0;
|
||||
|
||||
while (m_pos < m_size)
|
||||
{
|
||||
if (stringChar)
|
||||
{
|
||||
if (m_buffer[m_pos] == stringChar)
|
||||
{
|
||||
m_pos++;
|
||||
stringChar = 0;
|
||||
}
|
||||
else if (m_buffer[m_pos] == '\\' && m_buffer[m_pos + 1] == stringChar)
|
||||
{
|
||||
m_pos += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_buffer[m_pos] == '\n')
|
||||
m_lineNum++;
|
||||
m_pos++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SkipWhitespace();
|
||||
CheckInclude();
|
||||
CheckIncbin();
|
||||
|
||||
if (m_pos >= m_size)
|
||||
break;
|
||||
|
||||
char c = m_buffer[m_pos++];
|
||||
|
||||
if (c == '\n')
|
||||
m_lineNum++;
|
||||
else if (c == '"')
|
||||
stringChar = '"';
|
||||
else if (c == '\'')
|
||||
stringChar = '\'';
|
||||
else if (c == 0)
|
||||
FATAL_INPUT_ERROR("unexpected null character");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CFile::ConsumeHorizontalWhitespace()
|
||||
{
|
||||
if (m_buffer[m_pos] == '\t' || m_buffer[m_pos] == ' ')
|
||||
{
|
||||
m_pos++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CFile::ConsumeNewline()
|
||||
{
|
||||
if (m_buffer[m_pos] == '\n')
|
||||
{
|
||||
m_pos++;
|
||||
m_lineNum++;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_buffer[m_pos] == '\r' && m_buffer[m_pos + 1] == '\n')
|
||||
{
|
||||
m_pos += 2;
|
||||
m_lineNum++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CFile::ConsumeComment()
|
||||
{
|
||||
if (m_buffer[m_pos] == '/' && m_buffer[m_pos + 1] == '*')
|
||||
{
|
||||
m_pos += 2;
|
||||
while (m_buffer[m_pos] != '*' || m_buffer[m_pos + 1] != '/')
|
||||
{
|
||||
if (m_buffer[m_pos] == 0)
|
||||
return false;
|
||||
if (!ConsumeNewline())
|
||||
m_pos++;
|
||||
}
|
||||
m_pos += 2;
|
||||
return true;
|
||||
}
|
||||
else if (m_buffer[m_pos] == '/' && m_buffer[m_pos + 1] == '/')
|
||||
{
|
||||
m_pos += 2;
|
||||
while (!ConsumeNewline())
|
||||
{
|
||||
if (m_buffer[m_pos] == 0)
|
||||
return false;
|
||||
m_pos++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CFile::SkipWhitespace()
|
||||
{
|
||||
while (ConsumeHorizontalWhitespace() || ConsumeNewline() || ConsumeComment())
|
||||
;
|
||||
}
|
||||
|
||||
bool CFile::CheckIdentifier(const std::string& ident)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ident.length() && m_pos + i < (unsigned)m_size; i++)
|
||||
if (ident[i] != m_buffer[m_pos + i])
|
||||
return false;
|
||||
|
||||
return (i == ident.length());
|
||||
}
|
||||
|
||||
void CFile::CheckInclude()
|
||||
{
|
||||
if (m_buffer[m_pos] != '#')
|
||||
return;
|
||||
|
||||
std::string ident = "#include";
|
||||
|
||||
if (!CheckIdentifier(ident))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_pos += ident.length();
|
||||
|
||||
ConsumeHorizontalWhitespace();
|
||||
|
||||
std::string path = ReadPath();
|
||||
|
||||
if (!path.empty()) {
|
||||
m_includes.emplace(path);
|
||||
}
|
||||
}
|
||||
|
||||
void CFile::CheckIncbin()
|
||||
{
|
||||
// Optimization: assume most lines are not incbins
|
||||
if (!(m_buffer[m_pos+0] == 'I'
|
||||
&& m_buffer[m_pos+1] == 'N'
|
||||
&& m_buffer[m_pos+2] == 'C'
|
||||
&& m_buffer[m_pos+3] == 'B'
|
||||
&& m_buffer[m_pos+4] == 'I'
|
||||
&& m_buffer[m_pos+5] == 'N'
|
||||
&& m_buffer[m_pos+6] == '_'))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::string idents[6] = { "INCBIN_S8", "INCBIN_U8", "INCBIN_S16", "INCBIN_U16", "INCBIN_S32", "INCBIN_U32" };
|
||||
int incbinType = -1;
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
if (CheckIdentifier(idents[i]))
|
||||
{
|
||||
incbinType = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (incbinType == -1)
|
||||
return;
|
||||
|
||||
long oldPos = m_pos;
|
||||
long oldLineNum = m_lineNum;
|
||||
|
||||
m_pos += idents[incbinType].length();
|
||||
|
||||
SkipWhitespace();
|
||||
|
||||
if (m_buffer[m_pos] != '(')
|
||||
{
|
||||
m_pos = oldPos;
|
||||
m_lineNum = oldLineNum;
|
||||
return;
|
||||
}
|
||||
|
||||
m_pos++;
|
||||
|
||||
while (true)
|
||||
{
|
||||
SkipWhitespace();
|
||||
|
||||
std::string path = ReadPath();
|
||||
|
||||
SkipWhitespace();
|
||||
|
||||
m_incbins.emplace(path);
|
||||
|
||||
if (m_buffer[m_pos] != ',')
|
||||
break;
|
||||
|
||||
m_pos++;
|
||||
}
|
||||
|
||||
if (m_buffer[m_pos] != ')')
|
||||
FATAL_INPUT_ERROR("expected ')'");
|
||||
|
||||
m_pos++;
|
||||
|
||||
}
|
||||
|
||||
std::string CFile::ReadPath()
|
||||
{
|
||||
if (m_buffer[m_pos] != '"')
|
||||
{
|
||||
if (m_buffer[m_pos] == '<')
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
FATAL_INPUT_ERROR("expected '\"' or '<'");
|
||||
}
|
||||
|
||||
m_pos++;
|
||||
|
||||
int startPos = m_pos;
|
||||
|
||||
while (m_buffer[m_pos] != '"')
|
||||
{
|
||||
if (m_buffer[m_pos] == 0)
|
||||
{
|
||||
if (m_pos >= m_size)
|
||||
FATAL_INPUT_ERROR("unexpected EOF in path string");
|
||||
else
|
||||
FATAL_INPUT_ERROR("unexpected null character in path string");
|
||||
}
|
||||
|
||||
if (m_buffer[m_pos] == '\r' || m_buffer[m_pos] == '\n')
|
||||
FATAL_INPUT_ERROR("unexpected end of line character in path string");
|
||||
|
||||
if (m_buffer[m_pos] == '\\')
|
||||
FATAL_INPUT_ERROR("unexpected escape in path string");
|
||||
|
||||
m_pos++;
|
||||
}
|
||||
|
||||
m_pos++;
|
||||
|
||||
return std::string(m_buffer + startPos, m_pos - 1 - startPos);
|
||||
}
|
57
tools/scaninc/c_file.h
Normal file
57
tools/scaninc/c_file.h
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright(c) 2017 YamaArashi
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef C_FILE_H
|
||||
#define C_FILE_H
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <memory>
|
||||
#include "scaninc.h"
|
||||
|
||||
class CFile
|
||||
{
|
||||
public:
|
||||
CFile(std::string path);
|
||||
~CFile();
|
||||
void FindIncbins();
|
||||
const std::set<std::string>& GetIncbins() { return m_incbins; }
|
||||
const std::set<std::string>& GetIncludes() { return m_includes; }
|
||||
|
||||
private:
|
||||
char *m_buffer;
|
||||
int m_pos;
|
||||
int m_size;
|
||||
int m_lineNum;
|
||||
std::string m_path;
|
||||
std::set<std::string> m_incbins;
|
||||
std::set<std::string> m_includes;
|
||||
|
||||
bool ConsumeHorizontalWhitespace();
|
||||
bool ConsumeNewline();
|
||||
bool ConsumeComment();
|
||||
void SkipWhitespace();
|
||||
bool CheckIdentifier(const std::string& ident);
|
||||
void CheckInclude();
|
||||
void CheckIncbin();
|
||||
std::string ReadPath();
|
||||
};
|
||||
|
||||
#endif // C_FILE_H
|
128
tools/scaninc/scaninc.cpp
Normal file
128
tools/scaninc/scaninc.cpp
Normal file
@ -0,0 +1,128 @@
|
||||
// Copyright(c) 2015-2017 YamaArashi
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <list>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include "scaninc.h"
|
||||
#include "source_file.h"
|
||||
|
||||
bool CanOpenFile(std::string path)
|
||||
{
|
||||
FILE *fp = std::fopen(path.c_str(), "rb");
|
||||
|
||||
if (fp == NULL)
|
||||
return false;
|
||||
|
||||
std::fclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *const USAGE = "Usage: scaninc [-I INCLUDE_PATH] FILE_PATH\n";
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
std::queue<std::string> filesToProcess;
|
||||
std::set<std::string> dependencies;
|
||||
|
||||
std::vector<std::string> includeDirs;
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
while (argc > 1)
|
||||
{
|
||||
std::string arg(argv[0]);
|
||||
if (arg.substr(0, 2) == "-I")
|
||||
{
|
||||
std::string includeDir = arg.substr(2);
|
||||
if (includeDir.empty())
|
||||
{
|
||||
argc--;
|
||||
argv++;
|
||||
includeDir = std::string(argv[0]);
|
||||
}
|
||||
if (!includeDir.empty() && includeDir.back() != '/')
|
||||
{
|
||||
includeDir += '/';
|
||||
}
|
||||
includeDirs.push_back(includeDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
FATAL_ERROR(USAGE);
|
||||
}
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (argc != 1) {
|
||||
FATAL_ERROR(USAGE);
|
||||
}
|
||||
|
||||
std::string initialPath(argv[0]);
|
||||
|
||||
filesToProcess.push(initialPath);
|
||||
|
||||
while (!filesToProcess.empty())
|
||||
{
|
||||
std::string filePath = filesToProcess.front();
|
||||
SourceFile file(filePath);
|
||||
filesToProcess.pop();
|
||||
|
||||
includeDirs.push_back(file.GetSrcDir());
|
||||
for (auto incbin : file.GetIncbins())
|
||||
{
|
||||
dependencies.insert(incbin);
|
||||
}
|
||||
for (auto include : file.GetIncludes())
|
||||
{
|
||||
bool exists = false;
|
||||
std::string path("");
|
||||
for (auto includeDir : includeDirs)
|
||||
{
|
||||
path = includeDir + include;
|
||||
if (CanOpenFile(path))
|
||||
{
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!exists && (file.FileType() == SourceFileType::Asm || file.FileType() == SourceFileType::Inc))
|
||||
{
|
||||
path = include;
|
||||
}
|
||||
bool inserted = dependencies.insert(path).second;
|
||||
if (inserted && exists)
|
||||
{
|
||||
filesToProcess.push(path);
|
||||
}
|
||||
}
|
||||
includeDirs.pop_back();
|
||||
}
|
||||
|
||||
for (const std::string &path : dependencies)
|
||||
{
|
||||
std::printf("%s\n", path.c_str());
|
||||
}
|
||||
}
|
59
tools/scaninc/scaninc.h
Normal file
59
tools/scaninc/scaninc.h
Normal file
@ -0,0 +1,59 @@
|
||||
// Copyright(c) 2015-2017 YamaArashi
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef SCANINC_H
|
||||
#define SCANINC_H
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
#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
|
||||
|
||||
#endif // SCANINC_H
|
130
tools/scaninc/source_file.cpp
Normal file
130
tools/scaninc/source_file.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
// Copyright(c) 2019 Phlosioneer
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#include <new>
|
||||
#include "source_file.h"
|
||||
|
||||
|
||||
SourceFileType GetFileType(std::string& path)
|
||||
{
|
||||
std::size_t pos = path.find_last_of('.');
|
||||
|
||||
if (pos == std::string::npos)
|
||||
FATAL_ERROR("no file extension in path \"%s\"\n", path.c_str());
|
||||
|
||||
std::string extension = path.substr(pos + 1);
|
||||
|
||||
if (extension == "c")
|
||||
return SourceFileType::Cpp;
|
||||
else if (extension == "s")
|
||||
return SourceFileType::Asm;
|
||||
else if (extension == "h")
|
||||
return SourceFileType::Header;
|
||||
else if (extension == "inc")
|
||||
return SourceFileType::Inc;
|
||||
else
|
||||
FATAL_ERROR("Unrecognized extension \"%s\"\n", extension.c_str());
|
||||
|
||||
// Unreachable
|
||||
return SourceFileType::Cpp;
|
||||
}
|
||||
|
||||
std::string GetDir(std::string& path)
|
||||
{
|
||||
std::size_t slash = path.rfind('/');
|
||||
|
||||
if (slash != std::string::npos)
|
||||
return path.substr(0, slash + 1);
|
||||
else
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
SourceFile::SourceFile(std::string path)
|
||||
{
|
||||
m_file_type = GetFileType(path);
|
||||
|
||||
m_src_dir = GetDir(path);
|
||||
|
||||
if (m_file_type == SourceFileType::Cpp
|
||||
|| m_file_type == SourceFileType::Header)
|
||||
{
|
||||
new (&m_source_file.c_file) CFile(path);
|
||||
m_source_file.c_file.FindIncbins();
|
||||
}
|
||||
else
|
||||
{
|
||||
AsmFile file(path);
|
||||
std::set<std::string> incbins;
|
||||
std::set<std::string> includes;
|
||||
|
||||
IncDirectiveType incDirectiveType;
|
||||
std::string outputPath;
|
||||
|
||||
while ((incDirectiveType = file.ReadUntilIncDirective(outputPath)) != IncDirectiveType::None)
|
||||
{
|
||||
if (incDirectiveType == IncDirectiveType::Include)
|
||||
includes.insert(outputPath);
|
||||
else
|
||||
incbins.insert(outputPath);
|
||||
}
|
||||
|
||||
new (&m_source_file.asm_wrapper) SourceFile::InnerUnion::AsmWrapper{incbins, includes};
|
||||
}
|
||||
}
|
||||
|
||||
SourceFileType SourceFile::FileType()
|
||||
{
|
||||
return m_file_type;
|
||||
}
|
||||
|
||||
SourceFile::~SourceFile()
|
||||
{
|
||||
if (m_file_type == SourceFileType::Cpp || m_file_type == SourceFileType::Header)
|
||||
{
|
||||
m_source_file.c_file.~CFile();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_source_file.asm_wrapper.asm_incbins.~set();
|
||||
m_source_file.asm_wrapper.asm_includes.~set();
|
||||
}
|
||||
}
|
||||
|
||||
const std::set<std::string>& SourceFile::GetIncbins()
|
||||
{
|
||||
if (m_file_type == SourceFileType::Cpp || m_file_type == SourceFileType::Header)
|
||||
return m_source_file.c_file.GetIncbins();
|
||||
else
|
||||
return m_source_file.asm_wrapper.asm_incbins;
|
||||
}
|
||||
|
||||
const std::set<std::string>& SourceFile::GetIncludes()
|
||||
{
|
||||
if (m_file_type == SourceFileType::Cpp || m_file_type == SourceFileType::Header)
|
||||
return m_source_file.c_file.GetIncludes();
|
||||
else
|
||||
return m_source_file.asm_wrapper.asm_includes;
|
||||
}
|
||||
|
||||
std::string& SourceFile::GetSrcDir()
|
||||
{
|
||||
return m_src_dir;
|
||||
}
|
||||
|
72
tools/scaninc/source_file.h
Normal file
72
tools/scaninc/source_file.h
Normal file
@ -0,0 +1,72 @@
|
||||
// Copyright(c) 2019 Phlosioneer
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef SOURCE_FILE_H
|
||||
#define SOURCE_FILE_H
|
||||
|
||||
#include <string>
|
||||
#include "scaninc.h"
|
||||
#include "asm_file.h"
|
||||
#include "c_file.h"
|
||||
|
||||
enum class SourceFileType
|
||||
{
|
||||
Cpp,
|
||||
Header,
|
||||
Asm,
|
||||
Inc
|
||||
};
|
||||
|
||||
SourceFileType GetFileType(std::string& path);
|
||||
|
||||
class SourceFile
|
||||
{
|
||||
public:
|
||||
|
||||
SourceFile(std::string path);
|
||||
~SourceFile();
|
||||
SourceFile(SourceFile const&) = delete;
|
||||
SourceFile(SourceFile&&) = delete;
|
||||
SourceFile& operator =(SourceFile const&) = delete;
|
||||
SourceFile& operator =(SourceFile&&) = delete;
|
||||
bool HasIncbins();
|
||||
const std::set<std::string>& GetIncbins();
|
||||
const std::set<std::string>& GetIncludes();
|
||||
std::string& GetSrcDir();
|
||||
SourceFileType FileType();
|
||||
|
||||
private:
|
||||
union InnerUnion {
|
||||
CFile c_file;
|
||||
struct AsmWrapper {
|
||||
std::set<std::string> asm_incbins;
|
||||
std::set<std::string> asm_includes;
|
||||
} asm_wrapper;
|
||||
|
||||
// Construction and destruction handled by SourceFile.
|
||||
InnerUnion() {};
|
||||
~InnerUnion() {};
|
||||
} m_source_file;
|
||||
SourceFileType m_file_type;
|
||||
std::string m_src_dir;
|
||||
};
|
||||
|
||||
#endif // SOURCE_FILE_H
|
||||
|
Reference in New Issue
Block a user