migrate to new scaninc, remove unused deps, fix make tidy

This commit is contained in:
Oliver Bell committed 2025-01-30 01:11:49 +00:00
1 parent e831653f1a
commit 55a73a6e6d
39 files changed
+343 -27013

No files matched your search

-1
View File
@@ -1 +0,0 @@
bin2c
-19
View File
@@ -1,19 +0,0 @@
Copyright (c) 2016 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.
-16
View File
@@ -1,16 +0,0 @@
CC = gcc
CFLAGS = -Wall -Wextra -Werror -std=c11 -O2 -s
.PHONY: all clean
SRCS = bin2c.c
all: bin2c
@:
bin2c: $(SRCS)
$(CC) $(CFLAGS) $(SRCS) -o $@ $(LDFLAGS)
clean:
$(RM) bin2c bin2c.exe
-201
View File
@@ -1,201 +0,0 @@
// Copyright(c) 2015-2016 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#ifdef _MSC_VER
#define FATAL_ERROR(format, ...) \
do \
{ \
fprintf(stderr, format, __VA_ARGS__); \
exit(1); \
} while (0)
#else
#define FATAL_ERROR(format, ...) \
do \
{ \
fprintf(stderr, format, ##__VA_ARGS__); \
exit(1); \
} while (0)
#endif // _MSC_VER
unsigned char *ReadWholeFile(char *path, int *size)
{
FILE *fp = fopen(path, "rb");
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
fseek(fp, 0, SEEK_END);
*size = ftell(fp);
unsigned char *buffer = malloc(*size);
if (buffer == NULL)
FATAL_ERROR("Failed to allocate memory for reading \"%s\".\n", path);
rewind(fp);
if (fread(buffer, *size, 1, fp) != 1)
FATAL_ERROR("Failed to read \"%s\".\n", path);
fclose(fp);
return buffer;
}
int ExtractData(unsigned char *buffer, int offset, int size)
{
switch (size)
{
case 1:
return buffer[offset];
case 2:
return (buffer[offset + 1] << 8)
| buffer[offset];
case 4:
return (buffer[offset + 3] << 24)
| (buffer[offset + 2] << 16)
| (buffer[offset + 1] << 8)
| buffer[offset];
default:
FATAL_ERROR("Invalid size passed to ExtractData.\n");
}
}
int main(int argc, char **argv)
{
if (argc < 3)
FATAL_ERROR("Usage: bin2c INPUT_FILE VAR_NAME [OPTIONS...]\n");
int fileSize;
unsigned char *buffer = ReadWholeFile(argv[1], &fileSize);
char *var_name = argv[2];
int col = 1;
int pad = 0;
int size = 1;
bool isSigned = false;
bool isStatic = false;
bool isDecimal = false;
for (int i = 3; i < argc; i++)
{
if (!strcmp(argv[i], "-col"))
{
i++;
if (i >= argc)
FATAL_ERROR("Missing argument after '-col'.\n");
col = atoi(argv[i]);
}
else if (!strcmp(argv[i], "-pad"))
{
i++;
if (i >= argc)
FATAL_ERROR("Missing argument after '-pad'.\n");
pad = atoi(argv[i]);
}
else if (!strcmp(argv[i], "-size"))
{
i++;
if (i >= argc)
FATAL_ERROR("Missing argument after '-size'.\n");
size = atoi(argv[i]);
if (size != 1 && size != 2 && size != 4)
FATAL_ERROR("Size must be 1, 2, or 4.\n");
}
else if (!strcmp(argv[i], "-signed"))
{
isSigned = true;
isDecimal = true;
}
else if (!strcmp(argv[i], "-static"))
{
isStatic = true;
}
else if (!strcmp(argv[i], "-decimal"))
{
isDecimal = true;
}
else
{
FATAL_ERROR("Unrecognized option '%s'.\n", argv[i]);
}
}
if ((fileSize & (size - 1)) != 0)
FATAL_ERROR("Size %d doesn't evenly divide file size %d.\n", size, fileSize);
printf("// Generated file. Do not edit.\n\n");
if (isStatic)
printf("static ");
printf("const ");
if (isSigned)
printf("s%d ", 8 * size);
else
printf("u%d ", 8 * size);
printf("%s[] =\n{", var_name);
int count = fileSize / size;
int offset = 0;
for (int i = 0; i < count; i++)
{
if (i % col == 0)
printf("\n ");
int data = ExtractData(buffer, offset, size);
offset += size;
if (isDecimal)
{
if (isSigned)
printf("%*d, ", pad, data);
else
printf("%*uu, ", pad, data);
}
else
{
printf("%#*xu, ", pad, data);
}
}
printf("\n};\n");
return 0;
}
-1
View File
@@ -1 +0,0 @@
jsonproc
-20
View File
@@ -1,20 +0,0 @@
CXX := g++
CXXFLAGS := -Wall -std=c++11 -O2
INCLUDES := -I .
SRCS := jsonproc.cpp
HEADERS := jsonproc.h inja.hpp nlohmann/json.hpp
.PHONY: clean all
all: jsonproc
@:
jsonproc: $(SRCS) $(HEADERS)
$(CXX) $(CXXFLAGS) $(INCLUDES) $(SRCS) -o $@ $(LDFLAGS)
clean:
$(RM) jsonproc jsonproc.exe
-3529
View File
File diff suppressed because it is too large. Load diff
-116
View File
@@ -1,116 +0,0 @@
// jsonproc.cpp
#include "jsonproc.h"
#include <map>
#include <string>
using std::string; using std::to_string;
#include <inja.hpp>
using namespace inja;
using json = nlohmann::json;
std::map<string, string> customVars;
void set_custom_var(string key, string value)
{
customVars[key] = value;
}
string get_custom_var(string key)
{
return customVars[key];
}
int main(int argc, char *argv[])
{
if (argc != 4)
FATAL_ERROR("USAGE: jsonproc <json-filepath> <template-filepath> <output-filepath>\n");
string jsonfilepath = argv[1];
string templateFilepath = argv[2];
string outputFilepath = argv[3];
Environment env;
// Add custom command callbacks.
env.add_callback("doNotModifyHeader", 0, [jsonfilepath, templateFilepath](Arguments& args) {
return "//\n// DO NOT MODIFY THIS FILE! It is auto-generated from " + jsonfilepath +" and Inja template " + templateFilepath + "\n//\n";
});
env.add_callback("contains", 2, [](Arguments& args) {
string word = args.at(0)->get<string>();
string check = args.at(1)->get<string>();
return word.find(check) != std::string::npos;
});
env.add_callback("subtract", 2, [](Arguments& args) {
int minuend = args.at(0)->get<int>();
int subtrahend = args.at(1)->get<int>();
return minuend - subtrahend;
});
env.add_callback("setVar", 2, [=](Arguments& args) {
string key = args.at(0)->get<string>();
string value = args.at(1)->get<string>();
set_custom_var(key, value);
return "";
});
env.add_callback("setVarInt", 2, [=](Arguments& args) {
string key = args.at(0)->get<string>();
string value = to_string(args.at(1)->get<int>());
set_custom_var(key, value);
return "";
});
env.add_callback("getVar", 1, [=](Arguments& args) {
string key = args.at(0)->get<string>();
return get_custom_var(key);
});
env.add_callback("concat", 2, [](Arguments& args) {
string first = args.at(0)->get<string>();
string second = args.at(1)->get<string>();
return first + second;
});
env.add_callback("removePrefix", 2, [](Arguments& args) {
string rawValue = args.at(0)->get<string>();
string prefix = args.at(1)->get<string>();
string::size_type i = rawValue.find(prefix);
if (i != 0)
return rawValue;
return rawValue.erase(0, prefix.length());
});
env.add_callback("removeSuffix", 2, [](Arguments& args) {
string rawValue = args.at(0)->get<string>();
string suffix = args.at(1)->get<string>();
string::size_type i = rawValue.rfind(suffix);
if (i == string::npos)
return rawValue;
return rawValue.substr(0, i);
});
// single argument is a json object
env.add_callback("isEmpty", 1, [](Arguments& args) {
return args.at(0)->empty();
});
try
{
env.write_with_json_file(templateFilepath, jsonfilepath, outputFilepath);
}
catch (const std::exception& e)
{
FATAL_ERROR("JSONPROC_ERROR: %s\n", e.what());
}
return 0;
}
-32
View File
@@ -1,32 +0,0 @@
// jsonproc.h
#ifndef JSONPROC_H
#define JSONPROC_H
#include <cstdlib>
#include <cstdio>
using std::fprintf; using std::exit;
#include <cstdlib>
#ifdef _MSC_VER
#define FATAL_ERROR(format, ...) \
do \
{ \
fprintf(stderr, format, __VA_ARGS__); \
exit(1); \
} while (0)
#else
#define FATAL_ERROR(format, ...) \
do \
{ \
fprintf(stderr, format, ##__VA_ARGS__); \
exit(1); \
} while (0)
#endif // _MSC_VER
#endif // JSONPROC_H
-20842
View File
File diff suppressed because it is too large. Load diff
-1
View File
@@ -1 +0,0 @@
ramscrgen
-19
View File
@@ -1,19 +0,0 @@
Copyright (c) 2016 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.
-18
View File
@@ -1,18 +0,0 @@
CXX := g++
CXXFLAGS := -std=c++11 -O2 -s -Wall -Wno-switch -Werror
SRCS := main.cpp sym_file.cpp elf.cpp
HEADERS := ramscrgen.h sym_file.h elf.h char_util.h
.PHONY: all clean
all: ramscrgen
@:
ramscrgen: $(SRCS) $(HEADERS)
$(CXX) $(CXXFLAGS) $(SRCS) -o $@ $(LDFLAGS)
clean:
$(RM) ramscrgen ramscrgen.exe
-71
View File
@@ -1,71 +0,0 @@
// Copyright(c) 2016 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 CHAR_UTIL_H
#define CHAR_UTIL_H
#include <cstdint>
#include <cassert>
inline bool IsAscii(unsigned char c)
{
return (c < 128);
}
inline bool IsAsciiAlpha(unsigned char c)
{
return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'));
}
inline bool IsAsciiDigit(unsigned char c)
{
return (c >= '0' && c <= '9');
}
inline bool IsAsciiHexDigit(unsigned char c)
{
return ((c >= '0' && c <= '9')
|| (c >= 'a' && c <= 'f')
|| (c >= 'A' && c <= 'F'));
}
inline bool IsAsciiAlphanum(unsigned char c)
{
return (IsAsciiAlpha(c) || IsAsciiDigit(c));
}
inline bool IsAsciiPrintable(unsigned char c)
{
return (c >= ' ' && c <= '~');
}
// Returns whether the character can start the identifier of a "{FOO}" constant in strings.
inline bool IsIdentifierStartingChar(unsigned char c)
{
return IsAsciiAlpha(c) || c == '_';
}
// Returns whether the character can be used in the identifier of a "{FOO}" constant in strings.
inline bool IsIdentifierChar(unsigned char c)
{
return IsAsciiAlphanum(c) || c == '_';
}
#endif // CHAR_UTIL_H
-195
View File
@@ -1,195 +0,0 @@
#include <cstdio>
#include <cstring>
#include <cstdint>
#include <map>
#include <vector>
#include <string>
#include "ramscrgen.h"
#include "elf.h"
#define SHN_COMMON 0xFFF2
static std::string s_elfPath;
static FILE *s_file;
static std::uint32_t s_sectionHeaderOffset;
static int s_sectionHeaderEntrySize;
static int s_sectionCount;
static int s_shstrtabIndex;
static std::uint32_t s_symtabOffset;
static std::uint32_t s_strtabOffset;
static std::uint32_t s_symbolCount;
struct Symbol
{
std::uint32_t nameOffset;
std::uint32_t size;
};
static void Seek(long offset)
{
if (std::fseek(s_file, offset, SEEK_SET) != 0)
FATAL_ERROR("error: failed to seek to %ld in \"%s\"", offset, s_elfPath.c_str());
}
static void Skip(long offset)
{
if (std::fseek(s_file, offset, SEEK_CUR) != 0)
FATAL_ERROR("error: failed to skip %ld bytes in \"%s\"", offset, s_elfPath.c_str());
}
static std::uint32_t ReadInt8()
{
int c = std::fgetc(s_file);
if (c < 0)
FATAL_ERROR("error: unexpected EOF when reading ELF file \"%s\"\n", s_elfPath.c_str());
return c;
}
static std::uint32_t ReadInt16()
{
std::uint32_t val = 0;
val |= ReadInt8();
val |= ReadInt8() << 8;
return val;
}
static std::uint32_t ReadInt32()
{
std::uint32_t val = 0;
val |= ReadInt8();
val |= ReadInt8() << 8;
val |= ReadInt8() << 16;
val |= ReadInt8() << 24;
return val;
}
static std::string ReadString()
{
std::string s;
char c;
while ((c = ReadInt8()) != 0)
s += c;
return s;
}
static void VerifyElfIdent()
{
char expectedMagic[4] = { 0x7F, 'E', 'L', 'F' };
char magic[4];
if (std::fread(magic, 4, 1, s_file) != 1)
FATAL_ERROR("error: failed to read ELF magic from \"%s\"\n", s_elfPath.c_str());
if (std::memcmp(magic, expectedMagic, 4) != 0)
FATAL_ERROR("error: ELF magic did not match in \"%s\"\n", s_elfPath.c_str());
if (std::fgetc(s_file) != 1)
FATAL_ERROR("error: \"%s\" not 32-bit ELF\n", s_elfPath.c_str());
if (std::fgetc(s_file) != 1)
FATAL_ERROR("error: \"%s\" not little-endian ELF\n", s_elfPath.c_str());
}
static void ReadElfHeader()
{
Seek(0x20);
s_sectionHeaderOffset = ReadInt32();
Seek(0x2E);
s_sectionHeaderEntrySize = ReadInt16();
s_sectionCount = ReadInt16();
s_shstrtabIndex = ReadInt16();
}
static std::string GetSectionName(std::uint32_t shstrtabOffset, int index)
{
Seek(s_sectionHeaderOffset + s_sectionHeaderEntrySize * index);
std::uint32_t nameOffset = ReadInt32();
Seek(shstrtabOffset + nameOffset);
return ReadString();
}
static void FindTableOffsets()
{
s_symtabOffset = 0;
s_strtabOffset = 0;
Seek(s_sectionHeaderOffset + s_sectionHeaderEntrySize * s_shstrtabIndex + 0x10);
std::uint32_t shstrtabOffset = ReadInt32();
for (int i = 0; i < s_sectionCount; i++)
{
std::string name = GetSectionName(shstrtabOffset, i);
if (name == ".symtab")
{
if (s_symtabOffset)
FATAL_ERROR("error: mutiple .symtab sections found in \"%s\"\n", s_elfPath.c_str());
Seek(s_sectionHeaderOffset + s_sectionHeaderEntrySize * i + 0x10);
s_symtabOffset = ReadInt32();
std::uint32_t size = ReadInt32();
s_symbolCount = size / 16;
}
else if (name == ".strtab")
{
if (s_strtabOffset)
FATAL_ERROR("error: mutiple .strtab sections found in \"%s\"\n", s_elfPath.c_str());
Seek(s_sectionHeaderOffset + s_sectionHeaderEntrySize * i + 0x10);
s_strtabOffset = ReadInt32();
}
}
if (!s_symtabOffset)
FATAL_ERROR("error: couldn't find .symtab section in \"%s\"\n", s_elfPath.c_str());
if (!s_strtabOffset)
FATAL_ERROR("error: couldn't find .strtab section in \"%s\"\n", s_elfPath.c_str());
}
std::map<std::string, std::uint32_t> GetCommonSymbols(std::string path)
{
s_elfPath = path;
std::map<std::string, std::uint32_t> commonSymbols;
s_file = std::fopen(s_elfPath.c_str(), "rb");
if (s_file == NULL)
FATAL_ERROR("error: failed to open \"%s\" for reading\n", path.c_str());
VerifyElfIdent();
ReadElfHeader();
FindTableOffsets();
std::vector<Symbol> commonSymbolVec;
Seek(s_symtabOffset);
for (std::uint32_t i = 0; i < s_symbolCount; i++)
{
Symbol sym;
sym.nameOffset = ReadInt32();
Skip(4);
sym.size = ReadInt32();
Skip(2);
std::uint16_t sectionIndex = ReadInt16();
if (sectionIndex == SHN_COMMON)
commonSymbolVec.push_back(sym);
}
for (const Symbol& sym : commonSymbolVec)
{
Seek(s_strtabOffset + sym.nameOffset);
std::string name = ReadString();
commonSymbols[name] = sym.size;
}
return commonSymbols;
}
-30
View File
@@ -1,30 +0,0 @@
// Copyright(c) 2016 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 ELF_H
#define ELF_H
#include <cstdint>
#include <map>
#include <string>
std::map<std::string, std::uint32_t> GetCommonSymbols(std::string path);
#endif // ELF_H
-173
View File
@@ -1,173 +0,0 @@
// Copyright(c) 2016 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 <cstring>
#include <string>
#include "ramscrgen.h"
#include "sym_file.h"
#include "elf.h"
void HandleCommonInclude(std::string filename, std::string sourcePath, std::string symOrderPath, std::string lang)
{
auto commonSymbols = GetCommonSymbols(sourcePath + "/" + filename);
std::size_t dotIndex = filename.find_last_of('.');
if (dotIndex == std::string::npos)
FATAL_ERROR("error: \"%s\" doesn't have a file extension\n", filename.c_str());
std::string symOrderFilename = filename.substr(0, dotIndex + 1) + "txt";
SymFile symFile(symOrderPath + "/" + symOrderFilename);
while (!symFile.IsAtEnd())
{
symFile.HandleLangConditional(lang);
std::string label = symFile.GetLabel(false);
if (label.length() == 0)
{
unsigned long length;
if (symFile.ReadInteger(length))
{
if (length & 3)
symFile.RaiseWarning("gap length %d is not multiple of 4", length);
printf(". += 0x%lX;\n", length);
}
}
else
{
if (commonSymbols.count(label) == 0)
symFile.RaiseError("no common symbol named \"%s\"", label.c_str());
unsigned long size = commonSymbols[label];
int alignment = 4;
if (size > 4)
alignment = 8;
if (size > 8)
alignment = 16;
printf(". = ALIGN(%d);\n", alignment);
printf("%s = .;\n", label.c_str());
printf(". += 0x%lX;\n", size);
}
symFile.ExpectEmptyRestOfLine();
}
}
void ConvertSymFile(std::string filename, std::string sectionName, std::string lang, bool common, std::string sourcePath, std::string commonSymPath)
{
SymFile symFile(filename);
while (!symFile.IsAtEnd())
{
symFile.HandleLangConditional(lang);
Directive directive = symFile.GetDirective();
switch (directive)
{
case Directive::Include:
{
std::string incFilename = symFile.ReadPath();
symFile.ExpectEmptyRestOfLine();
printf(". = ALIGN(4);\n");
if (common)
HandleCommonInclude(incFilename, sourcePath, commonSymPath, lang);
else
printf("%s(%s);\n", incFilename.c_str(), sectionName.c_str());
break;
}
case Directive::Space:
{
unsigned long length;
if (!symFile.ReadInteger(length))
symFile.RaiseError("expected integer after .space directive");
symFile.ExpectEmptyRestOfLine();
printf(". += 0x%lX;\n", length);
break;
}
case Directive::Align:
{
unsigned long amount;
if (!symFile.ReadInteger(amount))
symFile.RaiseError("expected integer after .align directive");
if (amount > 4)
symFile.RaiseError("max alignment amount is 4");
amount = 1UL << amount;
symFile.ExpectEmptyRestOfLine();
printf(". = ALIGN(%lu);\n", amount);
break;
}
case Directive::Unknown:
{
std::string label = symFile.GetLabel();
if (label.length() != 0)
{
printf("%s = .;\n", label.c_str());
}
symFile.ExpectEmptyRestOfLine();
break;
}
}
}
}
int main(int argc, char **argv)
{
if (argc < 4)
{
fprintf(stderr, "Usage: %s SECTION_NAME SYM_FILE LANG [-c SRC_PATH,COMMON_SYM_PATH]", argv[0]);
return 1;
}
bool common = false;
std::string sectionName = std::string(argv[1]);
std::string symFileName = std::string(argv[2]);
std::string lang = std::string(argv[3]);
std::string sourcePath;
std::string commonSymPath;
if (argc > 4)
{
if (std::strcmp(argv[4], "-c") != 0)
FATAL_ERROR("error: unrecognized argument \"%s\"\n", argv[4]);
if (argc < 6)
FATAL_ERROR("error: missing SRC_PATH,COMMON_SYM_PATH after \"-c\"\n");
common = true;
std::string paths = std::string(argv[5]);
std::size_t commaPos = paths.find(',');
if (commaPos == std::string::npos)
FATAL_ERROR("error: missing comma in argument after \"-c\"\n");
sourcePath = paths.substr(0, commaPos);
commonSymPath = paths.substr(commaPos + 1);
}
ConvertSymFile(symFileName, sectionName, lang, common, sourcePath, commonSymPath);
return 0;
}
-49
View File
@@ -1,49 +0,0 @@
// Copyright(c) 2016 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 RAMSCRGEN_H
#define RAMSCRGEN_H
#include <cstdio>
#include <cstdlib>
#ifdef _MSC_VER
#define FATAL_ERROR(format, ...) \
do \
{ \
std::fprintf(stderr, format, __VA_ARGS__); \
std::exit(1); \
} while (0)
#else
#define FATAL_ERROR(format, ...) \
do \
{ \
std::fprintf(stderr, format, ##__VA_ARGS__); \
std::exit(1); \
} while (0)
#endif // _MSC_VER
const int kMaxPath = 256;
#endif // RAMSCRGEN_H
-492
View File
@@ -1,492 +0,0 @@
// Copyright(c) 2016 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 <cstdarg>
#include <climits>
#include "ramscrgen.h"
#include "sym_file.h"
#include "char_util.h"
SymFile::SymFile(std::string filename) : m_filename(filename)
{
FILE *fp = std::fopen(filename.c_str(), "rb");
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for reading.\n", filename.c_str());
std::fseek(fp, 0, SEEK_END);
m_size = std::ftell(fp);
if (m_size < 0)
FATAL_ERROR("File size of \"%s\" is less than zero.\n", filename.c_str());
m_buffer = new char[m_size + 1];
std::rewind(fp);
if (std::fread(m_buffer, m_size, 1, fp) != 1)
FATAL_ERROR("Failed to read \"%s\".\n", filename.c_str());
m_buffer[m_size] = 0;
std::fclose(fp);
m_pos = 0;
m_lineNum = 1;
m_lineStart = 0;
m_inLangConditional = false;
RemoveComments();
}
SymFile::SymFile(SymFile&& other) : m_filename(std::move(other.m_filename))
{
m_buffer = other.m_buffer;
m_pos = other.m_pos;
m_size = other.m_size;
m_lineNum = other.m_lineNum;
m_lineStart = other.m_lineStart;
other.m_buffer = nullptr;
}
SymFile::~SymFile()
{
delete[] m_buffer;
}
// Removes comments to simplify further processing.
// It stops upon encountering a null character,
// which may or may not be the end of file marker.
// If it's not, the error will be caught later.
void SymFile::RemoveComments()
{
long pos = 0;
char stringChar = 0;
for (;;)
{
if (m_buffer[pos] == 0)
return;
if (stringChar != 0)
{
if (m_buffer[pos] == '\\' && m_buffer[pos + 1] == stringChar)
{
pos += 2;
}
else
{
if (m_buffer[pos] == stringChar)
stringChar = 0;
pos++;
}
}
else if (m_buffer[pos] == '@' && (pos == 0 || m_buffer[pos - 1] != '\\'))
{
while (m_buffer[pos] != '\n' && m_buffer[pos] != 0)
m_buffer[pos++] = ' ';
}
else if (m_buffer[pos] == '/' && m_buffer[pos + 1] == '*')
{
m_buffer[pos++] = ' ';
m_buffer[pos++] = ' ';
char commentStringChar = 0;
for (;;)
{
if (m_buffer[pos] == 0)
return;
if (commentStringChar != 0)
{
if (m_buffer[pos] == '\\' && m_buffer[pos + 1] == commentStringChar)
{
m_buffer[pos++] = ' ';
m_buffer[pos++] = ' ';
}
else
{
if (m_buffer[pos] == commentStringChar)
commentStringChar = 0;
if (m_buffer[pos] != '\n')
m_buffer[pos] = ' ';
pos++;
}
}
else
{
if (m_buffer[pos] == '*' && m_buffer[pos + 1] == '/')
{
m_buffer[pos++] = ' ';
m_buffer[pos++] = ' ';
break;
}
else
{
if (m_buffer[pos] == '"' || m_buffer[pos] == '\'')
commentStringChar = m_buffer[pos];
if (m_buffer[pos] != '\n')
m_buffer[pos] = ' ';
pos++;
}
}
}
}
else
{
if (m_buffer[pos] == '"' || m_buffer[pos] == '\'')
stringChar = m_buffer[pos];
pos++;
}
}
}
// Checks if we're at a particular directive and if so, consumes it.
// Returns whether the directive was found.
bool SymFile::CheckForDirective(std::string name)
{
long i;
long length = static_cast<long>(name.length());
for (i = 0; i < length && m_pos + i < m_size; i++)
if (name[i] != m_buffer[m_pos + i])
return false;
if (i < length)
return false;
m_pos += length;
return true;
}
// Checks if we're at a known directive and if so, consumes it.
// Returns which directive was found.
Directive SymFile::GetDirective()
{
SkipWhitespace();
if (CheckForDirective(".include"))
return Directive::Include;
else if (CheckForDirective(".space"))
return Directive::Space;
else if (CheckForDirective(".align"))
return Directive::Align;
else
return Directive::Unknown;
}
// Checks if we're at label.
// Returns the name if so and an empty string if not.
std::string SymFile::GetLabel(bool requireColon)
{
long start = m_pos;
long pos = m_pos;
if (IsIdentifierStartingChar(m_buffer[pos]))
{
pos++;
while (IsIdentifierChar(m_buffer[pos]))
pos++;
}
if (requireColon)
{
if (m_buffer[pos] == ':')
{
if (pos != start)
m_pos = pos + 1;
}
else
{
pos = start;
}
}
else
{
m_pos = pos;
}
return std::string(&m_buffer[start], pos - start);
}
// Skips tabs and spaces.
void SymFile::SkipWhitespace()
{
while (m_buffer[m_pos] == '\t' || m_buffer[m_pos] == ' ')
m_pos++;
}
// Reads include path.
std::string SymFile::ReadPath()
{
SkipWhitespace();
if (m_buffer[m_pos] != '"')
RaiseError("expected file path");
m_pos++;
int length = 0;
long startPos = m_pos;
while (m_buffer[m_pos] != '"')
{
unsigned char c = m_buffer[m_pos++];
if (c == 0)
{
if (m_pos >= m_size)
RaiseError("unexpected EOF in include string");
else
RaiseError("unexpected null character in include string");
}
if (!IsAsciiPrintable(c))
RaiseError("unexpected character '\\x%02X' in include string", c);
// Don't bother allowing any escape sequences.
if (c == '\\')
{
c = m_buffer[m_pos];
RaiseError("unexpected escape '\\%c' in include string", c);
}
length++;
if (length > kMaxPath)
RaiseError("path is too long");
}
m_pos++; // Go past the right quote.
return std::string(&m_buffer[startPos], length);
}
// If we're at a comma, consumes it.
// Returns whether a comma was found.
bool SymFile::ConsumeComma()
{
if (m_buffer[m_pos] == ',')
{
m_pos++;
return true;
}
return false;
}
// Converts digit character to numerical value.
static int ConvertDigit(char c, int radix)
{
int digit;
if (c >= '0' && c <= '9')
digit = c - '0';
else if (c >= 'A' && c <= 'F')
digit = 10 + c - 'A';
else if (c >= 'a' && c <= 'f')
digit = 10 + c - 'a';
else
return -1;
return (digit < radix) ? digit : -1;
}
// Reads an integer.
bool SymFile::ReadInteger(unsigned long& n)
{
SkipWhitespace();
if (!IsAsciiDigit(m_buffer[m_pos]))
return false;
int startPos = m_pos;
int radix = 10;
if (m_buffer[m_pos] == '0' && m_buffer[m_pos + 1] == 'x')
{
radix = 16;
m_pos += 2;
}
unsigned long cutoff = ULONG_MAX / radix;
unsigned long cutoffRemainder = ULONG_MAX % radix;
int digit;
n = 0;
while ((digit = ConvertDigit(m_buffer[m_pos], radix)) != -1)
{
if (n < cutoff || (n == cutoff && (unsigned long)digit <= cutoffRemainder))
{
n = n * radix + digit;
}
else
{
m_pos++;
while (ConvertDigit(m_buffer[m_pos], radix) != -1)
m_pos++;
RaiseError("integer is too large (%s)", std::string(&m_buffer[startPos], m_pos - startPos).c_str());
}
m_pos++;
}
return true;
}
// Asserts that the rest of the line is empty and moves to the next one.
void SymFile::ExpectEmptyRestOfLine()
{
SkipWhitespace();
if (m_buffer[m_pos] == 0)
{
if (m_pos >= m_size)
RaiseWarning("file doesn't end with newline");
else
RaiseError("unexpected null character");
}
else if (m_buffer[m_pos] == '\n')
{
m_pos++;
m_lineStart = m_pos;
m_lineNum++;
}
else if (m_buffer[m_pos] == '\r')
{
RaiseError("only Unix-style LF newlines are supported");
}
else
{
RaiseError("junk at end of line");
}
}
void SymFile::SkipLine()
{
while (m_buffer[m_pos] != 0 && m_buffer[m_pos] != '\n')
m_pos++;
if (m_buffer[m_pos] == '\n')
m_pos++;
}
// Checks if we're at the end of the file.
bool SymFile::IsAtEnd()
{
return (m_pos >= m_size);
}
void SymFile::HandleLangConditional(std::string lang)
{
if (m_buffer[m_pos] != '#')
return;
m_pos++;
if (CheckForDirective("begin"))
{
if (m_inLangConditional)
RaiseError("already inside language conditional");
SkipWhitespace();
std::string label = GetLabel(false);
if (label.length() == 0)
RaiseError("no language name after #begin");
ExpectEmptyRestOfLine();
if (lang == label)
{
m_inLangConditional = true;
}
else
{
while (!IsAtEnd() && m_buffer[m_pos] != '#')
SkipLine();
if (m_buffer[m_pos] != '#')
RaiseError("unterminated language conditional");
m_pos++;
if (!CheckForDirective("end"))
RaiseError("expected #end");
ExpectEmptyRestOfLine();
}
}
else if (CheckForDirective("end"))
{
if (!m_inLangConditional)
RaiseError("not inside language conditional");
m_inLangConditional = false;
ExpectEmptyRestOfLine();
}
else
{
RaiseError("unknown # directive");
}
}
// Reports a diagnostic message.
void SymFile::ReportDiagnostic(const char* type, const char* format, std::va_list args)
{
const int bufferSize = 1024;
char buffer[bufferSize];
std::vsnprintf(buffer, bufferSize, format, args);
std::fprintf(stderr, "%s:%ld: %s: %s\n", m_filename.c_str(), m_lineNum, type, buffer);
}
#define DO_REPORT(type) \
do \
{ \
std::va_list args; \
va_start(args, format); \
ReportDiagnostic(type, format, args); \
va_end(args); \
} while (0)
// Reports an error diagnostic and terminates the program.
void SymFile::RaiseError(const char* format, ...)
{
DO_REPORT("error");
std::exit(1);
}
// Reports a warning diagnostic.
void SymFile::RaiseWarning(const char* format, ...)
{
DO_REPORT("warning");
}
-1
View File
@@ -1 +0,0 @@
rsfont
-19
View File
@@ -1,19 +0,0 @@
Copyright (c) 2015-2016 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.
-20
View File
@@ -1,20 +0,0 @@
CC = gcc
CFLAGS = -Wall -Wextra -Werror -std=c11 -O2 -s -DPNG_SKIP_SETJMP_CHECK
CFLAGS += $(shell pkg-config --cflags libpng)
LIBS = -lpng -lz
LDFLAGS += $(shell pkg-config --libs-only-L libpng)
SRCS = main.c convert_png.c util.c font.c
.PHONY: all clean
all: rsfont
@:
rsfont: $(SRCS) convert_png.h gfx.h global.h util.h font.h
$(CC) $(CFLAGS) $(SRCS) -o $@ $(LDFLAGS) $(LIBS)
clean:
$(RM) rsfont rsfont.exe
-169
View File
@@ -1,169 +0,0 @@
// Copyright (c) 2015 YamaArashi
#include <stdio.h>
#include <setjmp.h>
#include <png.h>
#include "global.h"
#include "convert_png.h"
#include "gfx.h"
void ReadPng(char *path, struct Image *image)
{
FILE *fp = fopen(path, "rb");
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
unsigned char sig[8];
if (fread(sig, 8, 1, fp) != 1)
FATAL_ERROR("Failed to read PNG signature from \"%s\".\n", path);
if (png_sig_cmp(sig, 0, 8))
FATAL_ERROR("\"%s\" does not have a valid PNG signature.\n", path);
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr)
FATAL_ERROR("Failed to create PNG read struct.\n");
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
FATAL_ERROR("Failed to create PNG info struct.\n");
if (setjmp(png_jmpbuf(png_ptr)))
FATAL_ERROR("Failed to init I/O for reading \"%s\".\n", path);
png_init_io(png_ptr, fp);
png_set_sig_bytes(png_ptr, 8);
png_read_info(png_ptr, info_ptr);
int bit_depth = png_get_bit_depth(png_ptr, info_ptr);
if (bit_depth != image->bitDepth)
FATAL_ERROR("\"%s\" has a bit depth of %d, but the expected bit depth is %d.\n", path, bit_depth, image->bitDepth);
int color_type = png_get_color_type(png_ptr, info_ptr);
if (color_type != PNG_COLOR_TYPE_GRAY && color_type != PNG_COLOR_TYPE_PALETTE)
FATAL_ERROR("\"%s\" has an unsupported color type.\n", path);
// Check if the image has a palette so that we can tell if the colors need to be inverted later.
// Don't read the palette because it's not needed for now.
image->hasPalette = (color_type == PNG_COLOR_TYPE_PALETTE);
image->width = png_get_image_width(png_ptr, info_ptr);
image->height = png_get_image_height(png_ptr, info_ptr);
int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
image->pixels = malloc(image->height * rowbytes);
if (image->pixels == NULL)
FATAL_ERROR("Failed to allocate pixel buffer.\n");
png_bytepp row_pointers = malloc(image->height * sizeof(png_bytep));
if (row_pointers == NULL)
FATAL_ERROR("Failed to allocate row pointers.\n");
for (int i = 0; i < image->height; i++)
row_pointers[i] = (png_bytep)(image->pixels + (i * rowbytes));
if (setjmp(png_jmpbuf(png_ptr)))
FATAL_ERROR("Error reading from \"%s\".\n", path);
png_read_image(png_ptr, row_pointers);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
free(row_pointers);
fclose(fp);
}
void SetPngPalette(png_structp png_ptr, png_infop info_ptr, struct Palette *palette)
{
png_colorp colors = malloc(palette->numColors * sizeof(png_color));
if (colors == NULL)
FATAL_ERROR("Failed to allocate PNG palette.\n");
for (int i = 0; i < palette->numColors; i++) {
colors[i].red = palette->colors[i].red;
colors[i].green = palette->colors[i].green;
colors[i].blue = palette->colors[i].blue;
}
png_set_PLTE(png_ptr, info_ptr, colors, palette->numColors);
free(colors);
}
void WritePng(char *path, struct Image *image)
{
FILE *fp = fopen(path, "wb");
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for writing.\n", path);
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr)
FATAL_ERROR("Failed to create PNG write struct.\n");
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
FATAL_ERROR("Failed to create PNG info struct.\n");
if (setjmp(png_jmpbuf(png_ptr)))
FATAL_ERROR("Failed to init I/O for writing \"%s\".\n", path);
png_init_io(png_ptr, fp);
if (setjmp(png_jmpbuf(png_ptr)))
FATAL_ERROR("Error writing header for \"%s\".\n", path);
int color_type = image->hasPalette ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_GRAY;
png_set_IHDR(png_ptr, info_ptr, image->width, image->height,
image->bitDepth, color_type, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
if (image->hasPalette) {
SetPngPalette(png_ptr, info_ptr, &image->palette);
if (image->hasTransparency) {
png_byte trans = 0;
png_set_tRNS(png_ptr, info_ptr, &trans, 1, 0);
}
}
png_write_info(png_ptr, info_ptr);
png_bytepp row_pointers = malloc(image->height * sizeof(png_bytep));
if (row_pointers == NULL)
FATAL_ERROR("Failed to allocate row pointers.\n");
int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
for (int i = 0; i < image->height; i++)
row_pointers[i] = (png_bytep)(image->pixels + (i * rowbytes));
if (setjmp(png_jmpbuf(png_ptr)))
FATAL_ERROR("Error writing \"%s\".\n", path);
png_write_image(png_ptr, row_pointers);
if (setjmp(png_jmpbuf(png_ptr)))
FATAL_ERROR("Error ending write of \"%s\".\n", path);
png_write_end(png_ptr, NULL);
fclose(fp);
png_destroy_write_struct(&png_ptr, &info_ptr);
free(row_pointers);
}
-11
View File
@@ -1,11 +0,0 @@
// Copyright (c) 2015 YamaArashi
#ifndef CONVERT_PNG_H
#define CONVERT_PNG_H
#include "gfx.h"
void ReadPng(char *path, struct Image *image);
void WritePng(char *path, struct Image *image);
#endif // CONVERT_PNG_H
-455
View File
@@ -1,455 +0,0 @@
// Copyright(c) 2015-2016 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 <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "global.h"
#include "font.h"
#include "gfx.h"
#include "util.h"
unsigned char gFontPalette[][3] =
{
{0xFF, 0xFF, 0xFF}, // bg (white)
{0x38, 0x38, 0x38}, // fg (dark grey)
{0xD8, 0xD8, 0xD8}, // shadow (light grey)
};
void ConvertFromTiles1Bpp(unsigned char *src, unsigned char *dest, int numGlyphs, int layout)
{
for (int glyph = 0; glyph < numGlyphs; glyph++)
{
if (layout == 0)
{
for (int i = 0; i < 8; i++)
{
uint8_t srcRow = src[(glyph * 8) + i];
for (int j = 0; j < 8; j++)
{
int x = ((glyph % 16) * 8) + j;
int y = ((glyph / 16) * 8) + i;
dest[(y * 128) + x] = (srcRow >> (7 - j)) & 1;
}
}
}
else
{
// layout type 1
int tile1Offset = glyph * 16;
int tile2Offset = tile1Offset + 8;
for (int i = 0; i < 8; i++)
{
uint8_t srcRow = src[tile1Offset + i];
for (int j = 0; j < 8; j++)
{
int x = ((glyph % 16) * 8) + j;
int y = ((glyph / 16) * 16) + i;
dest[(y * 128) + x] = (srcRow >> (7 - j)) & 1;
}
}
for (int i = 0; i < 8; i++)
{
uint8_t srcRow = src[tile2Offset + i];
for (int j = 0; j < 8; j++)
{
int x = ((glyph % 16) * 8) + j;
int y = ((glyph / 16) * 16) + 8 + i;
dest[(y * 128) + x] = (srcRow >> (7 - j)) & 1;
}
}
}
}
}
void ConvertToTiles1Bpp(unsigned char *src, unsigned char *dest, int numGlyphs, int layout)
{
for (int glyph = 0; glyph < numGlyphs; glyph++)
{
if (layout == 0)
{
for (int i = 0; i < 8; i++)
{
uint8_t destRow = 0;
for (int j = 0; j < 8; j++)
{
int x = ((glyph % 16) * 8) + j;
int y = ((glyph / 16) * 8) + i;
unsigned char color = src[(y * 128) + x];
if (color > 1)
FATAL_ERROR("More than 2 colors in 1 BPP font.\n");
destRow <<= 1;
destRow |= color;
}
dest[(glyph * 8) + i] = destRow;
}
}
else
{
// layout type 1
int tile1Offset = glyph * 16;
int tile2Offset = tile1Offset + 8;
for (int i = 0; i < 8; i++)
{
uint8_t destRow = 0;
for (int j = 0; j < 8; j++)
{
int x = ((glyph % 16) * 8) + j;
int y = ((glyph / 16) * 16) + i;
unsigned char color = src[(y * 128) + x];
if (color > 1)
FATAL_ERROR("More than 2 colors in 1 BPP font.\n");
destRow <<= 1;
destRow |= color;
}
dest[tile1Offset + i] = destRow;
}
for (int i = 0; i < 8; i++)
{
uint8_t destRow = 0;
for (int j = 0; j < 8; j++)
{
int x = ((glyph % 16) * 8) + j;
int y = ((glyph / 16) * 16) + 8 + i;
unsigned char color = src[(y * 128) + x];
if (color > 1)
FATAL_ERROR("More than 2 colors in 1 BPP font.\n");
destRow <<= 1;
destRow |= color;
}
dest[tile2Offset + i] = destRow;
}
}
}
}
void ConvertFromTiles4Bpp(unsigned char *src, unsigned char *dest, int numGlyphs, int layout)
{
static unsigned char table[16] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1,
};
for (int glyph = 0; glyph < numGlyphs; glyph++)
{
if (layout == 0)
{
int offset = glyph * 32;
for (int i = 0; i < 8; i++)
{
uint32_t srcRow = (src[offset + 3] << 24)
| (src[offset + 2] << 16)
| (src[offset + 1] << 8)
| src[offset];
for (int j = 0; j < 8; j++)
{
int x = ((glyph % 16) * 8) + j;
int y = ((glyph / 16) * 8) + i;
dest[(y * 128) + x] = table[srcRow & 0xF];
srcRow >>= 4;
}
offset += 4;
}
}
else
{
int tile1Offset;
int tile2Offset;
if (layout == 1)
{
tile1Offset = glyph * 64;
tile2Offset = tile1Offset + 32;
}
else
{
tile1Offset = ((glyph / 16) * 1024) + ((glyph % 16) * 32);
tile2Offset = tile1Offset + 512;
}
for (int i = 0; i < 8; i++)
{
uint32_t srcRow = (src[tile1Offset + 3] << 24)
| (src[tile1Offset + 2] << 16)
| (src[tile1Offset + 1] << 8)
| src[tile1Offset];
for (int j = 0; j < 8; j++)
{
int x = ((glyph % 16) * 8) + j;
int y = ((glyph / 16) * 16) + i;
dest[(y * 128) + x] = table[srcRow & 0xF];
srcRow >>= 4;
}
tile1Offset += 4;
}
for (int i = 0; i < 8; i++)
{
uint32_t srcRow = (src[tile2Offset + 3] << 24)
| (src[tile2Offset + 2] << 16)
| (src[tile2Offset + 1] << 8)
| src[tile2Offset];
for (int j = 0; j < 8; j++)
{
int x = ((glyph % 16) * 8) + j;
int y = ((glyph / 16) * 16) + 8 + i;
dest[(y * 128) + x] = table[srcRow & 0xF];
srcRow >>= 4;
}
tile2Offset += 4;
}
}
}
}
void ConvertToTiles4Bpp(unsigned char *src, unsigned char *dest, int numGlyphs, int layout)
{
static unsigned char table[3] =
{
0, 15, 14,
};
for (int glyph = 0; glyph < numGlyphs; glyph++)
{
if (layout == 0)
{
int offset = glyph * 32;
for (int i = 0; i < 8; i++)
{
uint32_t destRow = 0;
for (int j = 0; j < 8; j++)
{
int x = ((glyph % 16) * 8) + j;
int y = ((glyph / 16) * 8) + i;
unsigned char color = src[(y * 128) + x];
if (color > 2)
FATAL_ERROR("More than 3 colors in 4 BPP font.\n");
destRow >>= 4;
destRow |= (table[color] << 28);
}
dest[offset] = destRow & 0xFF;
dest[offset + 1] = (destRow >> 8) & 0xFF;
dest[offset + 2] = (destRow >> 16) & 0xFF;
dest[offset + 3] = (destRow >> 24) & 0xFF;
offset += 4;
}
}
else
{
int tile1Offset;
int tile2Offset;
if (layout == 1)
{
tile1Offset = glyph * 64;
tile2Offset = tile1Offset + 32;
}
else
{
tile1Offset = ((glyph / 16) * 1024) + ((glyph % 16) * 32);
tile2Offset = tile1Offset + 512;
}
for (int i = 0; i < 8; i++)
{
uint32_t destRow = 0;
for (int j = 0; j < 8; j++)
{
int x = ((glyph % 16) * 8) + j;
int y = ((glyph / 16) * 16) + i;
unsigned char color = src[(y * 128) + x];
if (color > 2)
FATAL_ERROR("More than 3 colors in 4 BPP font.\n");
destRow >>= 4;
destRow |= (table[color] << 28);
}
dest[tile1Offset] = destRow & 0xFF;
dest[tile1Offset + 1] = (destRow >> 8) & 0xFF;
dest[tile1Offset + 2] = (destRow >> 16) & 0xFF;
dest[tile1Offset + 3] = (destRow >> 24) & 0xFF;
tile1Offset += 4;
}
for (int i = 0; i < 8; i++)
{
uint32_t destRow = 0;
for (int j = 0; j < 8; j++)
{
int x = ((glyph % 16) * 8) + j;
int y = ((glyph / 16) * 16) + 8 + i;
unsigned char color = src[(y * 128) + x];
if (color > 2)
FATAL_ERROR("More than 3 colors in 4 BPP font.\n");
destRow >>= 4;
destRow |= (table[color] << 28);
}
dest[tile2Offset] = destRow & 0xFF;
dest[tile2Offset + 1] = (destRow >> 8) & 0xFF;
dest[tile2Offset + 2] = (destRow >> 16) & 0xFF;
dest[tile2Offset + 3] = (destRow >> 24) & 0xFF;
tile2Offset += 4;
}
}
}
}
static void SetFontPalette(struct Image *image)
{
image->hasPalette = true;
image->palette.numColors = 3;
for (int i = 0; i < image->palette.numColors; i++)
{
image->palette.colors[i].red = gFontPalette[i][0];
image->palette.colors[i].green = gFontPalette[i][1];
image->palette.colors[i].blue = gFontPalette[i][2];
}
image->hasTransparency = false;
}
int CalcFileSize(int numGlyphs, int bpp, int layout)
{
if (layout == 2)
{
// assume 4 BPP
int numFullRows = numGlyphs / 16;
int remainder = numGlyphs % 16;
int fullRowsSize = numFullRows * 1024;
int remainderSize = 0;
if (remainder != 0)
remainderSize = 1024 - (16 - remainder) * 32;
return fullRowsSize + remainderSize;
}
else
{
int tilesPerGlyph = layout > 0 ? 2 : 1;
int bytesPerTile = 8 * bpp;
return numGlyphs * tilesPerGlyph * bytesPerTile;
}
}
void ReadFont(char *path, struct Image *image, int numGlyphs, int bpp, int layout)
{
int fileSize;
unsigned char *buffer = ReadWholeFile(path, &fileSize);
int expectedFileSize = CalcFileSize(numGlyphs, bpp, layout);
if (fileSize != expectedFileSize)
FATAL_ERROR("The file size is %d but should be %d.\n", fileSize, expectedFileSize);
int numRows = (numGlyphs + 15) / 16;
int rowHeight = layout > 0 ? 16 : 8;
image->width = 128;
image->height = numRows * rowHeight;
image->bitDepth = 8;
image->pixels = calloc(image->width * image->height, 1);
if (image->pixels == NULL)
FATAL_ERROR("Failed to allocate memory for font.\n");
if (bpp == 1)
ConvertFromTiles1Bpp(buffer, image->pixels, numGlyphs, layout);
else
ConvertFromTiles4Bpp(buffer, image->pixels, numGlyphs, layout);
free(buffer);
SetFontPalette(image);
}
void WriteFont(char *path, struct Image *image, int numGlyphs, int bpp, int layout)
{
if (image->width != 128)
FATAL_ERROR("The width of the font image (%d) is not 128.\n", image->width);
int numRows = (numGlyphs + 15) / 16;
int rowHeight = layout > 0 ? 16 : 8;
int expectedHeight = numRows * rowHeight;
if (image->height < expectedHeight)
FATAL_ERROR("The height of the font image (%d) is less than %d.\n", image->height, expectedHeight);
int fileSize = CalcFileSize(numGlyphs, bpp, layout);
unsigned char *buffer = calloc(fileSize, 1);
if (buffer == NULL)
FATAL_ERROR("Failed to allocate memory for font.\n");
if (bpp == 1)
ConvertToTiles1Bpp(image->pixels, buffer, numGlyphs, layout);
else
ConvertToTiles4Bpp(image->pixels, buffer, numGlyphs, layout);
WriteWholeFile(path, buffer, fileSize);
free(buffer);
}
-30
View File
@@ -1,30 +0,0 @@
// Copyright(c) 2015-2016 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 FONT_H
#define FONT_H
#include <stdbool.h>
#include "gfx.h"
void ReadFont(char *path, struct Image *image, int numGlyphs, int bpp, int layout);
void WriteFont(char *path, struct Image *image, int numGlyphs, int bpp, int layout);
#endif // FONT_H
-50
View File
@@ -1,50 +0,0 @@
// Copyright(c) 2015-2016 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 GFX_H
#define GFX_H
#include <stdint.h>
#include <stdbool.h>
struct Color
{
unsigned char red;
unsigned char green;
unsigned char blue;
};
struct Palette
{
struct Color colors[256];
int numColors;
};
struct Image {
int width;
int height;
int bitDepth;
unsigned char *pixels;
bool hasPalette;
struct Palette palette;
bool hasTransparency;
};
#endif // GFX_H
-31
View File
@@ -1,31 +0,0 @@
// Copyright (c) 2015 YamaArashi
#ifndef GLOBAL_H
#define GLOBAL_H
#include <stdio.h>
#include <stdlib.h>
#ifdef _MSC_VER
#define FATAL_ERROR(format, ...) \
do { \
fprintf(stderr, format, __VA_ARGS__); \
exit(1); \
} while (0)
#define UNUSED
#else
#define FATAL_ERROR(format, ...) \
do { \
fprintf(stderr, format, ##__VA_ARGS__); \
exit(1); \
} while (0)
#define UNUSED __attribute__((__unused__))
#endif // _MSC_VER
#endif // GLOBAL_H
-93
View File
@@ -1,93 +0,0 @@
// Copyright(c) 2015-2016 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 <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "global.h"
#include "util.h"
#include "gfx.h"
#include "convert_png.h"
#include "font.h"
int ExtensionToBpp(const char *extension)
{
if (!strcmp(extension, "1bpp"))
return 1;
else if (!strcmp(extension, "4bpp"))
return 4;
return 0;
}
int main(int argc, char **argv)
{
if (argc < 5)
FATAL_ERROR("Usage: rsfont INPUT_FILE OUTPUT_FILE NUM_GLYPHS LAYOUT_TYPE\n");
char *inputPath = argv[1];
char *outputPath = argv[2];
char *inputFileExtension = GetFileExtension(inputPath);
char *outputFileExtension = GetFileExtension(outputPath);
if (inputFileExtension == NULL)
FATAL_ERROR("Input file \"%s\" has no extension.\n", inputPath);
if (outputFileExtension == NULL)
FATAL_ERROR("Output file \"%s\" has no extension.\n", outputPath);
int numGlyphs;
int bpp;
int layout;
if (!ParseNumber(argv[3], NULL, 10, &numGlyphs))
FATAL_ERROR("Failed to parse number of glyphs.\n");
if (!ParseNumber(argv[4], NULL, 10, &layout))
FATAL_ERROR("Failed to parse layout type.\n");
if (layout < 0 || layout > 2)
FATAL_ERROR("Layout type %d is invalid. Layout type must be 0, 1, or 2.\n", layout);
bool toPng;
if (!strcmp(inputFileExtension, "png") && (bpp = ExtensionToBpp(outputFileExtension)) != 0)
toPng = false;
else if ((bpp = ExtensionToBpp(inputFileExtension)) != 0 && !strcmp(outputFileExtension, "png"))
toPng = true;
else
FATAL_ERROR("Don't know how to convert \"%s\" to \"%s\".\n", inputPath, outputPath);
if (bpp == 1 && layout == 2)
FATAL_ERROR("Layout type 2 is not supported with 1 BPP fonts.\n");
struct Image image;
if (toPng)
{
ReadFont(inputPath, &image, numGlyphs, bpp, layout);
WritePng(outputPath, &image);
}
else
{
image.bitDepth = 8;
ReadPng(inputPath, &image);
WriteFont(outputPath, &image, numGlyphs, bpp, layout);
}
}
-124
View File
@@ -1,124 +0,0 @@
// Copyright (c) 2015 YamaArashi
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <errno.h>
#include <limits.h>
#include "global.h"
#include "util.h"
bool ParseNumber(char *s, char **end, int radix, int *intValue)
{
char *localEnd;
if (end == NULL)
end = &localEnd;
errno = 0;
const long longValue = strtol(s, end, radix);
if (*end == s)
return false; // not a number
if ((longValue == LONG_MIN || longValue == LONG_MAX) && errno == ERANGE)
return false;
if (longValue > INT_MAX)
return false;
if (longValue < INT_MIN)
return false;
*intValue = (int)longValue;
return true;
}
char *GetFileExtension(char *path)
{
char *extension = path;
while (*extension != 0)
extension++;
while (extension > path && *extension != '.')
extension--;
if (extension == path)
return NULL;
extension++;
if (*extension == 0)
return NULL;
return extension;
}
unsigned char *ReadWholeFile(char *path, int *size)
{
FILE *fp = fopen(path, "rb");
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
fseek(fp, 0, SEEK_END);
*size = ftell(fp);
unsigned char *buffer = malloc(*size);
if (buffer == NULL)
FATAL_ERROR("Failed to allocate memory for reading \"%s\".\n", path);
rewind(fp);
if (fread(buffer, *size, 1, fp) != 1)
FATAL_ERROR("Failed to read \"%s\".\n", path);
fclose(fp);
return buffer;
}
unsigned char *ReadWholeFileZeroPadded(char *path, int *size, int padAmount)
{
FILE *fp = fopen(path, "rb");
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for reading.\n", path);
fseek(fp, 0, SEEK_END);
*size = ftell(fp);
unsigned char *buffer = calloc(*size + padAmount, 1);
if (buffer == NULL)
FATAL_ERROR("Failed to allocate memory for reading \"%s\".\n", path);
rewind(fp);
if (fread(buffer, *size, 1, fp) != 1)
FATAL_ERROR("Failed to read \"%s\".\n", path);
fclose(fp);
return buffer;
}
void WriteWholeFile(char *path, void *buffer, int bufferSize)
{
FILE *fp = fopen(path, "wb");
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for writing.\n", path);
if (fwrite(buffer, bufferSize, 1, fp) != 1)
FATAL_ERROR("Failed to write to \"%s\".\n", path);
fclose(fp);
}
-14
View File
@@ -1,14 +0,0 @@
// Copyright (c) 2015 YamaArashi
#ifndef UTIL_H
#define UTIL_H
#include <stdbool.h>
bool ParseNumber(char *s, char **end, int radix, int *intValue);
char *GetFileExtension(char *path);
unsigned char *ReadWholeFile(char *path, int *size);
unsigned char *ReadWholeFileZeroPadded(char *path, int *size, int padAmount);
void WriteWholeFile(char *path, void *buffer, int bufferSize);
#endif // UTIL_H
+11 -5
View File
@@ -1,17 +1,23 @@
CXX = g++
CXX ?= g++
CXXFLAGS = -Wall -Werror -std=c++11 -O2
SRCS = scaninc.cpp c_file.cpp asm_file.cpp
SRCS = scaninc.cpp c_file.cpp asm_file.cpp source_file.cpp
HEADERS := scaninc.h asm_file.h c_file.h
HEADERS := scaninc.h asm_file.h c_file.h source_file.h
.PHONY: all clean
all: scaninc
ifeq ($(OS),Windows_NT)
EXE := .exe
else
EXE :=
endif
all: scaninc$(EXE)
@:
scaninc: $(SRCS) $(HEADERS)
scaninc$(EXE): $(SRCS) $(HEADERS)
$(CXX) $(CXXFLAGS) $(SRCS) -o $@ $(LDFLAGS)
clean:
+8 -2
View File
@@ -36,6 +36,11 @@ AsmFile::AsmFile(std::string path)
m_size = std::ftell(fp);
if (m_size < 0)
FATAL_ERROR("File size of \"%s\" is less than zero.\n", path.c_str());
else if (m_size == 0)
return; // Empty file
m_buffer = new char[m_size];
std::rewind(fp);
@@ -51,7 +56,7 @@ AsmFile::AsmFile(std::string path)
AsmFile::~AsmFile()
{
delete[] m_buffer;
if (m_size > 0) delete[] m_buffer;
}
IncDirectiveType AsmFile::ReadUntilIncDirective(std::string &path)
@@ -64,7 +69,8 @@ IncDirectiveType AsmFile::ReadUntilIncDirective(std::string &path)
IncDirectiveType incDirectiveType = IncDirectiveType::None;
if (PeekChar() == '.')
char c = PeekChar();
if (c == '.' || c == '#')
{
m_pos++;
+6 -1
View File
@@ -33,6 +33,11 @@ CFile::CFile(std::string path)
m_size = std::ftell(fp);
if (m_size < 0)
FATAL_ERROR("File size of \"%s\" is less than zero.\n", path.c_str());
else if (m_size == 0)
return; // Empty file
m_buffer = new char[m_size + 1];
m_buffer[m_size] = 0;
@@ -49,7 +54,7 @@ CFile::CFile(std::string path)
CFile::~CFile()
{
delete[] m_buffer;
if (m_size > 0) delete[] m_buffer;
}
void CFile::FindIncbins()
+89 -68
View File
@@ -24,9 +24,11 @@
#include <queue>
#include <set>
#include <string>
#include <iostream>
#include <tuple>
#include <fstream>
#include "scaninc.h"
#include "asm_file.h"
#include "c_file.h"
#include "source_file.h"
bool CanOpenFile(std::string path)
{
@@ -39,14 +41,18 @@ bool CanOpenFile(std::string path)
return true;
}
const char *const USAGE = "Usage: scaninc [-I INCLUDE_PATH] FILE_PATH\n";
const char *const USAGE = "Usage: scaninc [-I INCLUDE_PATH] [-M DEPENDENCY_OUT_PATH] FILE_PATH\n";
int main(int argc, char **argv)
{
std::queue<std::string> filesToProcess;
std::set<std::string> dependencies;
std::set<std::string> dependencies_includes;
std::list<std::string> includeDirs;
std::vector<std::string> includeDirs;
bool makeformat = false;
std::string make_outfile;
argc--;
argv++;
@@ -63,12 +69,19 @@ int main(int argc, char **argv)
argv++;
includeDir = std::string(argv[0]);
}
if (includeDir.back() != '/')
if (!includeDir.empty() && includeDir.back() != '/')
{
includeDir += '/';
}
includeDirs.push_back(includeDir);
}
else if(arg.substr(0, 2) == "-M")
{
makeformat = true;
argc--;
argv++;
make_outfile = std::string(argv[0]);
}
else
{
FATAL_ERROR(USAGE);
@@ -83,83 +96,91 @@ int main(int argc, char **argv)
std::string initialPath(argv[0]);
std::size_t pos = initialPath.find_last_of('.');
filesToProcess.push(initialPath);
if (pos == std::string::npos)
FATAL_ERROR("no file extension in path \"%s\"\n", initialPath.c_str());
std::string extension = initialPath.substr(pos + 1);
std::string srcDir("");
std::size_t slash = initialPath.rfind('/');
if (slash != std::string::npos)
while (!filesToProcess.empty())
{
srcDir = initialPath.substr(0, slash + 1);
}
includeDirs.push_back(srcDir);
std::string filePath = filesToProcess.front();
SourceFile file(filePath);
filesToProcess.pop();
if (extension == "c" || extension == "h")
{
filesToProcess.push(initialPath);
while (!filesToProcess.empty())
includeDirs.push_back(file.GetSrcDir());
for (auto incbin : file.GetIncbins())
{
CFile file(filesToProcess.front());
filesToProcess.pop();
file.FindIncbins();
for (auto incbin : file.GetIncbins())
dependencies.insert(incbin);
}
for (auto include : file.GetIncludes())
{
bool exists = false;
std::string path("");
for (auto includeDir : includeDirs)
{
dependencies.insert(incbin);
}
for (auto include : file.GetIncludes())
{
for (auto includeDir : includeDirs)
path = includeDir + include;
if (CanOpenFile(path))
{
std::string path(includeDir + include);
if (CanOpenFile(path))
{
bool inserted = dependencies.insert(path).second;
if (inserted)
{
filesToProcess.push(path);
}
break;
}
exists = true;
break;
}
}
}
}
else if (extension == "s" || extension == "inc")
{
filesToProcess.push(initialPath);
while (!filesToProcess.empty())
{
AsmFile file(filesToProcess.front());
filesToProcess.pop();
IncDirectiveType incDirectiveType;
std::string path;
while ((incDirectiveType = file.ReadUntilIncDirective(path)) != IncDirectiveType::None)
if (!exists && (file.FileType() == SourceFileType::Asm || file.FileType() == SourceFileType::Inc))
{
bool inserted = dependencies.insert(path).second;
if (inserted
&& incDirectiveType == IncDirectiveType::Include
&& CanOpenFile(path))
filesToProcess.push(path);
path = include;
if (CanOpenFile(path))
exists = true;
}
if (!exists)
continue;
dependencies_includes.insert(path);
bool inserted = dependencies.insert(path).second;
if (inserted && exists)
{
filesToProcess.push(path);
}
}
includeDirs.pop_back();
}
if(!makeformat)
{
for (const std::string &path : dependencies)
{
std::printf("%s\n", path.c_str());
}
std::cout << std::endl;
}
else
{
FATAL_ERROR("unknown extension \"%s\"\n", extension.c_str());
}
// Write out make rules to a file
std::ofstream output(make_outfile);
for (const std::string &path : dependencies)
{
std::printf("%s\n", path.c_str());
// Print a make rule for the object file
size_t ext_pos = make_outfile.find_last_of(".");
auto object_file = make_outfile.substr(0, ext_pos + 1) + "o";
output << object_file.c_str() << ":";
for (const std::string &path : dependencies)
{
output << " " << path;
}
output << '\n';
// Dependency list rule.
// Although these rules are identical, they need to be separate, else make will trigger the rule again after the file is created for the first time.
output << make_outfile.c_str() << ":";
for (const std::string &path : dependencies_includes)
{
output << " " << path;
}
output << '\n';
// Dummy rules
// If a dependency is deleted, make will try to make it, instead of rescanning the dependencies before trying to do that.
for (const std::string &path : dependencies)
{
output << path << ":\n";
}
output.flush();
output.close();
}
}
+130
View 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;
}
+40 -39
View File
@@ -1,4 +1,4 @@
// Copyright(c) 2016 YamaArashi
// 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
@@ -18,54 +18,55 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef SYM_FILE_H
#define SYM_FILE_H
#ifndef SOURCE_FILE_H
#define SOURCE_FILE_H
#include <cstdarg>
#include <cstdint>
#include <string>
#include "ramscrgen.h"
#include "scaninc.h"
#include "asm_file.h"
#include "c_file.h"
enum class Directive
enum class SourceFileType
{
Include,
Space,
Align,
Unknown
Cpp,
Header,
Asm,
Inc
};
class SymFile
SourceFileType GetFileType(std::string& path);
class SourceFile
{
public:
SymFile(std::string filename);
SymFile(SymFile&& other);
SymFile(const SymFile&) = delete;
~SymFile();
Directive GetDirective();
std::string GetLabel(bool requireColon = true);
std::string ReadPath();
bool ReadInteger(unsigned long& value);
void ExpectEmptyRestOfLine();
void SkipLine();
bool IsAtEnd();
void HandleLangConditional(std::string lang);
void RaiseError(const char* format, ...);
void RaiseWarning(const char* format, ...);
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:
char* m_buffer;
long m_pos;
long m_size;
long m_lineNum;
long m_lineStart;
std::string m_filename;
bool m_inLangConditional;
union InnerUnion {
CFile c_file;
struct AsmWrapper {
std::set<std::string> asm_incbins;
std::set<std::string> asm_includes;
} asm_wrapper;
bool ConsumeComma();
void RemoveComments();
bool CheckForDirective(std::string name);
void SkipWhitespace();
void ReportDiagnostic(const char* type, const char* format, std::va_list args);
// Construction and destruction handled by SourceFile.
InnerUnion() {};
~InnerUnion() {};
} m_source_file;
SourceFileType m_file_type;
std::string m_src_dir;
};
#endif // SYM_FILE_H
#endif // SOURCE_FILE_H