diff options
| author | Marcus Huderle <huderlem@gmail.com> | 2017-11-03 18:00:47 -0700 | 
|---|---|---|
| committer | Marcus Huderle <huderlem@gmail.com> | 2017-11-03 18:14:15 -0700 | 
| commit | 415fb6738308a9bfa2217419d3861784dcd8e5d9 (patch) | |
| tree | 8793240342d37104610f34756f6fee9db706ee8f /tools | |
| parent | ae56f7859fe17915d3fb33713dfef2fe31fe2a1d (diff) | |
| parent | 1698e882b4760bcfe8cf91073cf7e46541ae6392 (diff) | |
Merge remote-tracking branch 'upstream/master' into pokenav
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/gbagfx/convert_png.c | 237 | ||||
| -rw-r--r-- | tools/gbagfx/convert_png.h | 1 | ||||
| -rw-r--r-- | tools/gbagfx/main.c | 9 | ||||
| -rw-r--r-- | tools/scaninc/c_file.cpp | 175 | ||||
| -rw-r--r-- | tools/scaninc/c_file.h | 6 | ||||
| -rw-r--r-- | tools/scaninc/scaninc.cpp | 94 | 
6 files changed, 329 insertions, 193 deletions
| diff --git a/tools/gbagfx/convert_png.c b/tools/gbagfx/convert_png.c index f6a30804a..37904318c 100644 --- a/tools/gbagfx/convert_png.c +++ b/tools/gbagfx/convert_png.c @@ -7,163 +7,206 @@  #include "convert_png.h"  #include "gfx.h" -void ReadPng(char *path, struct Image *image) +static FILE *PngReadOpen(char *path, png_structp *pngStruct, png_infop *pngInfo)  { -	FILE *fp = fopen(path, "rb"); +    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 (fp == NULL) -		FATAL_ERROR("Failed to open \"%s\" for reading.\n", path); +    if (setjmp(png_jmpbuf(png_ptr))) +        FATAL_ERROR("Failed to init I/O for reading \"%s\".\n", path); -	unsigned char sig[8]; +    png_init_io(png_ptr, fp); +    png_set_sig_bytes(png_ptr, 8); +    png_read_info(png_ptr, info_ptr); -	if (fread(sig, 8, 1, fp) != 1) -		FATAL_ERROR("Failed to read PNG signature from \"%s\".\n", path); +    *pngStruct = png_ptr; +    *pngInfo = info_ptr; -	if (png_sig_cmp(sig, 0, 8)) -		FATAL_ERROR("\"%s\" does not have a valid PNG signature.\n", path); +    return fp; +} + +void ReadPng(char *path, struct Image *image) +{ +    png_structp png_ptr; +    png_infop info_ptr; + +    FILE *fp = PngReadOpen(path, &png_ptr, &info_ptr); -	png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); +    int bit_depth = png_get_bit_depth(png_ptr, info_ptr); -	if (!png_ptr) -		FATAL_ERROR("Failed to create PNG read struct.\n"); +    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); -	png_infop info_ptr = png_create_info_struct(png_ptr); +    int color_type = png_get_color_type(png_ptr, info_ptr); -	if (!info_ptr) -		FATAL_ERROR("Failed to create PNG info struct.\n"); +    if (color_type != PNG_COLOR_TYPE_GRAY && color_type != PNG_COLOR_TYPE_PALETTE) +        FATAL_ERROR("\"%s\" has an unsupported color type.\n", path); -	if (setjmp(png_jmpbuf(png_ptr))) -		FATAL_ERROR("Failed to init I/O for reading \"%s\".\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); -	png_init_io(png_ptr, fp); -	png_set_sig_bytes(png_ptr, 8); -	png_read_info(png_ptr, info_ptr); +    image->width = png_get_image_width(png_ptr, info_ptr); +    image->height = png_get_image_height(png_ptr, info_ptr); -	int bit_depth = png_get_bit_depth(png_ptr, info_ptr); +    int rowbytes = png_get_rowbytes(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); +    image->pixels = malloc(image->height * rowbytes); -	int color_type = png_get_color_type(png_ptr, info_ptr); +    if (image->pixels == NULL) +        FATAL_ERROR("Failed to allocate pixel buffer.\n"); -	if (color_type != PNG_COLOR_TYPE_GRAY && color_type != PNG_COLOR_TYPE_PALETTE) -		FATAL_ERROR("\"%s\" has an unsupported color type.\n", path); +    png_bytepp row_pointers = malloc(image->height * sizeof(png_bytep)); -	// 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); +    if (row_pointers == NULL) +        FATAL_ERROR("Failed to allocate row pointers.\n"); -	image->width = png_get_image_width(png_ptr, info_ptr); -	image->height = png_get_image_height(png_ptr, info_ptr); +    for (int i = 0; i < image->height; i++) +        row_pointers[i] = (png_bytep)(image->pixels + (i * rowbytes)); -	int rowbytes = png_get_rowbytes(png_ptr, info_ptr); +    if (setjmp(png_jmpbuf(png_ptr))) +        FATAL_ERROR("Error reading from \"%s\".\n", path); -	image->pixels = malloc(image->height * rowbytes); +    png_read_image(png_ptr, row_pointers); -	if (image->pixels == NULL) -		FATAL_ERROR("Failed to allocate pixel buffer.\n"); +    png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + +    free(row_pointers); +    fclose(fp); +} + +void ReadPngPalette(char *path, struct Palette *palette) +{ +    png_structp png_ptr; +    png_infop info_ptr; +    png_colorp colors; +    int numColors; -	png_bytepp row_pointers = malloc(image->height * sizeof(png_bytep)); +    FILE *fp = PngReadOpen(path, &png_ptr, &info_ptr); -	if (row_pointers == NULL) -		FATAL_ERROR("Failed to allocate row pointers.\n"); +    if (png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_PALETTE) +        FATAL_ERROR("The image \"%s\" does not contain a palette.\n", path); -	for (int i = 0; i < image->height; i++) -		row_pointers[i] = (png_bytep)(image->pixels + (i * rowbytes)); +    if (png_get_PLTE(png_ptr, info_ptr, &colors, &numColors) != PNG_INFO_PLTE) +        FATAL_ERROR("Failed to retrieve palette from \"%s\".\n", path); -	if (setjmp(png_jmpbuf(png_ptr))) -		FATAL_ERROR("Error reading from \"%s\".\n", path); +    if (numColors > 256) +        FATAL_ERROR("Images with more than 256 colors are not supported.\n"); -	png_read_image(png_ptr, row_pointers); +    palette->numColors = numColors; +    for (int i = 0; i < numColors; i++) { +        palette->colors[i].red = colors[i].red; +        palette->colors[i].green = colors[i].green; +        palette->colors[i].blue = colors[i].blue; +    } -	png_destroy_read_struct(&png_ptr, &info_ptr, NULL); +    png_destroy_read_struct(&png_ptr, &info_ptr, NULL); -	free(row_pointers); -	fclose(fp); +    fclose(fp);  }  void SetPngPalette(png_structp png_ptr, png_infop info_ptr, struct Palette *palette)  { -	png_colorp colors = malloc(palette->numColors * sizeof(png_color)); +    png_colorp colors = malloc(palette->numColors * sizeof(png_color)); -	if (colors == NULL) -		FATAL_ERROR("Failed to allocate PNG palette.\n"); +    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; -	} +    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); +    png_set_PLTE(png_ptr, info_ptr, colors, palette->numColors); -	free(colors); +    free(colors);  }  void WritePng(char *path, struct Image *image)  { -	FILE *fp = fopen(path, "wb"); +    FILE *fp = fopen(path, "wb"); -	if (fp == NULL) -		FATAL_ERROR("Failed to open \"%s\" for writing.\n", path); +    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); +    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"); +    if (!png_ptr) +        FATAL_ERROR("Failed to create PNG write struct.\n"); -	png_infop info_ptr = png_create_info_struct(png_ptr); +    png_infop info_ptr = png_create_info_struct(png_ptr); -	if (!info_ptr) -		FATAL_ERROR("Failed to create PNG info struct.\n"); +    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); +    if (setjmp(png_jmpbuf(png_ptr))) +        FATAL_ERROR("Failed to init I/O for writing \"%s\".\n", path); -	png_init_io(png_ptr, fp); +    png_init_io(png_ptr, fp); -	if (setjmp(png_jmpbuf(png_ptr))) -		FATAL_ERROR("Error writing header for \"%s\".\n", path); +    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; +    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); +    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->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); -		} -	} +        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_write_info(png_ptr, info_ptr); -	png_bytepp row_pointers = malloc(image->height * sizeof(png_bytep)); +    png_bytepp row_pointers = malloc(image->height * sizeof(png_bytep)); -	if (row_pointers == NULL) -		FATAL_ERROR("Failed to allocate row pointers.\n"); +    if (row_pointers == NULL) +        FATAL_ERROR("Failed to allocate row pointers.\n"); -	int rowbytes = png_get_rowbytes(png_ptr, info_ptr); +    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)); +    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); +    if (setjmp(png_jmpbuf(png_ptr))) +        FATAL_ERROR("Error writing \"%s\".\n", path); -	png_write_image(png_ptr, row_pointers); +    png_write_image(png_ptr, row_pointers); -	if (setjmp(png_jmpbuf(png_ptr))) -		FATAL_ERROR("Error ending write of \"%s\".\n", path); +    if (setjmp(png_jmpbuf(png_ptr))) +        FATAL_ERROR("Error ending write of \"%s\".\n", path); -	png_write_end(png_ptr, NULL); +    png_write_end(png_ptr, NULL); -	fclose(fp); +    fclose(fp); -	png_destroy_write_struct(&png_ptr, &info_ptr); -	free(row_pointers); +    png_destroy_write_struct(&png_ptr, &info_ptr); +    free(row_pointers);  } diff --git a/tools/gbagfx/convert_png.h b/tools/gbagfx/convert_png.h index 55d3d6942..caf081b73 100644 --- a/tools/gbagfx/convert_png.h +++ b/tools/gbagfx/convert_png.h @@ -7,5 +7,6 @@  void ReadPng(char *path, struct Image *image);  void WritePng(char *path, struct Image *image); +void ReadPngPalette(char *path, struct Palette *palette);  #endif // CONVERT_PNG_H diff --git a/tools/gbagfx/main.c b/tools/gbagfx/main.c index 37d3441fe..97db60e84 100644 --- a/tools/gbagfx/main.c +++ b/tools/gbagfx/main.c @@ -134,6 +134,14 @@ void HandlePngToGbaCommand(char *inputPath, char *outputPath, int argc, char **a      ConvertPngToGba(inputPath, outputPath, numTiles, bitDepth);  } +void HandlePngToGbaPaletteCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED) +{ +    struct Palette palette; + +    ReadPngPalette(inputPath, &palette); +    WriteGbaPalette(outputPath, &palette); +} +  void HandleGbaToJascPaletteCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)  {      struct Palette palette; @@ -353,6 +361,7 @@ int main(int argc, char **argv)          { "png", "1bpp", HandlePngToGbaCommand },          { "png", "4bpp", HandlePngToGbaCommand },          { "png", "8bpp", HandlePngToGbaCommand }, +        { "png", "gbapal", HandlePngToGbaPaletteCommand },          { "gbapal", "pal", HandleGbaToJascPaletteCommand },          { "pal", "gbapal", HandleJascToGbaPaletteCommand },          { "latfont", "png", HandleLatinFontToPngCommand }, diff --git a/tools/scaninc/c_file.cpp b/tools/scaninc/c_file.cpp index b82276dd6..f7acc833f 100644 --- a/tools/scaninc/c_file.cpp +++ b/tools/scaninc/c_file.cpp @@ -45,8 +45,6 @@ CFile::CFile(std::string path)      m_pos = 0;      m_lineNum = 1; - -    RemoveComments();  }  CFile::~CFile() @@ -54,71 +52,6 @@ CFile::~CFile()      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 CFile::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] == '/' && 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++] = ' '; - -            for (;;) -            { -                if (m_buffer[pos] == 0) -                    return; - -                if (m_buffer[pos] == '*' && m_buffer[pos + 1] == '/') -                { -                    m_buffer[pos++] = ' '; -                    m_buffer[pos++] = ' '; -                    break; -                } -                else -                { -                    if (m_buffer[pos] != '\n') -                        m_buffer[pos] = ' '; -                    pos++; -                } -            } -        } -        else -        { -            if (m_buffer[pos] == '"' || m_buffer[pos] == '\'') -                stringChar = m_buffer[pos]; -            pos++; -        } -    } -} -  void CFile::FindIncbins()  {      char stringChar = 0; @@ -145,6 +78,8 @@ void CFile::FindIncbins()          }          else          { +            SkipWhitespace(); +            CheckInclude();              CheckIncbin();              if (m_pos >= m_size) @@ -177,6 +112,13 @@ bool CFile::ConsumeHorizontalWhitespace()  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; @@ -184,10 +126,33 @@ bool CFile::ConsumeNewline()          return true;      } -    if (m_buffer[m_pos] == '\n') +    return false; +} + +bool CFile::ConsumeComment() +{ +    if (m_buffer[m_pos] == '/' && m_buffer[m_pos + 1] == '*')      { -        m_pos++; -        m_lineNum++; +        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;      } @@ -196,7 +161,7 @@ bool CFile::ConsumeNewline()  void CFile::SkipWhitespace()  { -    while (ConsumeHorizontalWhitespace() || ConsumeNewline()) +    while (ConsumeHorizontalWhitespace() || ConsumeNewline() || ConsumeComment())          ;  } @@ -211,8 +176,43 @@ bool CFile::CheckIdentifier(const std::string& ident)      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; @@ -246,8 +246,28 @@ void CFile::CheckIncbin()      SkipWhitespace(); +    std::string path = ReadPath(); + +    SkipWhitespace(); + +    if (m_buffer[m_pos] != ')') +        FATAL_INPUT_ERROR("expected ')'"); + +    m_pos++; + +    m_incbins.emplace(path); +} + +std::string CFile::ReadPath() +{      if (m_buffer[m_pos] != '"') -        FATAL_INPUT_ERROR("expected double quote"); +    { +        if (m_buffer[m_pos] == '<') +        { +            return std::string(); +        } +        FATAL_INPUT_ERROR("expected '\"' or '<'"); +    }      m_pos++; @@ -272,16 +292,7 @@ void CFile::CheckIncbin()          m_pos++;      } -    std::string path(&m_buffer[startPos], m_pos - startPos); -      m_pos++; -    SkipWhitespace(); - -    if (m_buffer[m_pos] != ')') -        FATAL_INPUT_ERROR("expected ')'"); - -    m_pos++; - -    m_incbins.emplace(path); +    return std::string(m_buffer + startPos, m_pos - 1 - startPos);  } diff --git a/tools/scaninc/c_file.h b/tools/scaninc/c_file.h index 922cb4639..618901b85 100644 --- a/tools/scaninc/c_file.h +++ b/tools/scaninc/c_file.h @@ -33,6 +33,7 @@ public:      ~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; @@ -41,13 +42,16 @@ private:      int m_lineNum;      std::string m_path;      std::set<std::string> m_incbins; +    std::set<std::string> m_includes; -    void RemoveComments();      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 diff --git a/tools/scaninc/scaninc.cpp b/tools/scaninc/scaninc.cpp index b6f7ba767..3dc221479 100644 --- a/tools/scaninc/scaninc.cpp +++ b/tools/scaninc/scaninc.cpp @@ -20,7 +20,8 @@  #include <cstdio>  #include <cstdlib> -#include <stack> +#include <list> +#include <queue>  #include <set>  #include <string>  #include "scaninc.h" @@ -38,15 +39,49 @@ bool CanOpenFile(std::string path)      return true;  } +const char *const USAGE = "Usage: scaninc [-I INCLUDE_PATH] FILE_PATH\n"; +  int main(int argc, char **argv)  { -    if (argc < 2) -        FATAL_ERROR("Usage: scaninc FILE_PATH\n"); - -    std::stack<std::string> filesToProcess; +    std::queue<std::string> filesToProcess;      std::set<std::string> dependencies; -    std::string initialPath(argv[1]); +    std::list<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.back() != '/') +            { +                includeDir += '/'; +            } +            includeDirs.push_back(includeDir); +        } +        else +        { +            FATAL_ERROR(USAGE); +        } +        argc--; +        argv++; +    } + +    if (argc != 1) { +        FATAL_ERROR(USAGE); +    } + +    std::string initialPath(argv[0]);      std::size_t pos = initialPath.find_last_of('.'); @@ -55,20 +90,53 @@ int main(int argc, char **argv)      std::string extension = initialPath.substr(pos + 1); -    if (extension == "c") +    std::string srcDir(""); +    std::size_t slash = initialPath.rfind('/'); +    if (slash != std::string::npos)      { -        CFile file(initialPath); +        srcDir = initialPath.substr(0, slash + 1); +    } +    includeDirs.push_back(srcDir); + +    if (extension == "c" || extension == "h") +    { +        filesToProcess.push(initialPath); + +        while (!filesToProcess.empty()) +        { +            CFile file(filesToProcess.front()); +            filesToProcess.pop(); -        file.FindIncbins(); -        dependencies = file.GetIncbins(); +            file.FindIncbins(); +            for (auto incbin : file.GetIncbins()) +            { +                dependencies.insert(incbin); +            } +            for (auto include : file.GetIncludes()) +            { +                for (auto includeDir : includeDirs) +                { +                    std::string path(includeDir + include); +                    if (CanOpenFile(path)) +                    { +                        bool inserted = dependencies.insert(path).second; +                        if (inserted) +                        { +                            filesToProcess.push(path); +                        } +                        break; +                    } +                } +            } +        }      } -    else if (extension == "s") +    else if (extension == "s" || extension == "inc")      { -        filesToProcess.push(std::string(argv[1])); +        filesToProcess.push(initialPath);          while (!filesToProcess.empty())          { -            AsmFile file(filesToProcess.top()); +            AsmFile file(filesToProcess.front());              filesToProcess.pop(); | 
