summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2010-09-14 01:15:26 +0000
committer Aaron Giles <aaron@aarongiles.com>2010-09-14 01:15:26 +0000
commitdb797ba7913c0edfbc8a7d9fae4b1065d61a1ad2 (patch)
treef5c8c3043ab4acebdc2e45da7dc826990f9542b7
parent7d09104932a3e0e8cd9eb20e8296c26a907f0c6b (diff)
New build tool makedep.c, derived from src2html.c (really!).
Does basic dependency analysis and supports excluding paths. Makefile now supports a depend target which will run makedep on the src/$(TARGET) tree and create dependencies. It deliberately excludes the root of src/emu as well as the osd directories in order to keep the dependency file down to a reasonable size, so if a core header file changes, you still need to clean and build all.
-rw-r--r--.gitattributes1
-rw-r--r--makefile35
-rw-r--r--src/build/build.mak45
-rw-r--r--src/build/makedep.c542
4 files changed, 609 insertions, 14 deletions
diff --git a/.gitattributes b/.gitattributes
index 9e831d1f4b5..601eee91ba9 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -7,6 +7,7 @@ docs/windows.txt svneol=native#text/plain
/makefile svneol=native#text/plain
src/build/build.mak svneol=native#text/plain
src/build/file2str.c svneol=native#text/plain
+src/build/makedep.c svneol=native#text/plain
src/build/png2bdc.c svneol=native#text/plain
src/build/verinfo.c svneol=native#text/plain
src/emu/addrmap.c svneol=native#text/plain
diff --git a/makefile b/makefile
index 08b5823fd74..dbcd332cf42 100644
--- a/makefile
+++ b/makefile
@@ -489,7 +489,7 @@ COBJFLAGS += \
#-------------------------------------------------
# add core include paths
-CCOMFLAGS += \
+INCPATH += \
-I$(SRC)/$(TARGET) \
-I$(OBJ)/$(TARGET)/layout \
-I$(SRC)/emu \
@@ -500,6 +500,7 @@ CCOMFLAGS += \
-I$(SRC)/osd/$(OSD) \
+
#-------------------------------------------------
# archiving flags
#-------------------------------------------------
@@ -585,7 +586,7 @@ LIBS =
# add expat XML library
ifeq ($(BUILD_EXPAT),1)
-CCOMFLAGS += -I$(SRC)/lib/expat
+INCPATH += -I$(SRC)/lib/expat
EXPAT = $(OBJ)/libexpat.a
else
LIBS += -lexpat
@@ -594,7 +595,7 @@ endif
# add ZLIB compression library
ifeq ($(BUILD_ZLIB),1)
-CCOMFLAGS += -I$(SRC)/lib/zlib
+INCPATH += -I$(SRC)/lib/zlib
ZLIB = $(OBJ)/libz.a
else
LIBS += -lz
@@ -643,6 +644,7 @@ include $(SRC)/build/build.mak
include $(SRC)/tools/tools.mak
# combine the various definitions to one
+CCOMFLAGS += $(INCPATH)
CDEFS = $(DEFS)
@@ -655,6 +657,22 @@ emulator: maketree $(BUILD) $(EMULATOR)
buildtools: maketree $(BUILD)
+# In order to keep dependencies reasonable, we exclude objects in the base of
+# $(SRC)/emu, as well as all the OSD objects and anything in the $(OBJ) tree
+depend: maketree $(MAKEDEP_TARGET)
+ @echo Rebuilding depend.mak...
+ $(MAKEDEP) -I. $(INCPATH) -X$(SRC)/emu -X$(SRC)/osd/... -X$(OBJ)/... src/mame > depend.mak
+
+INCPATH += \
+ -I$(SRC)/$(TARGET) \
+ -I$(OBJ)/$(TARGET)/layout \
+ -I$(SRC)/emu \
+ -I$(OBJ)/emu \
+ -I$(OBJ)/emu/layout \
+ -I$(SRC)/lib/util \
+ -I$(SRC)/osd \
+ -I$(SRC)/osd/$(OSD) \
+
tools: maketree $(TOOLS)
maketree: $(sort $(OBJDIRS))
@@ -725,11 +743,11 @@ $(OBJ)/%.s: $(SRC)/%.c | $(OSPREBUILD)
@echo Compiling $<...
$(CC) $(CDEFS) $(CFLAGS) -S $< -o $@
-$(OBJ)/%.lh: $(SRC)/%.lay $(FILE2STR)
+$(OBJ)/%.lh: $(SRC)/%.lay $(FILE2STR_TARGET)
@echo Converting $<...
@$(FILE2STR) $< $@ layout_$(basename $(notdir $<))
-$(OBJ)/%.fh: $(SRC)/%.png $(PNG2BDC) $(FILE2STR)
+$(OBJ)/%.fh: $(SRC)/%.png $(PNG2BDC_TARGET) $(FILE2STR_TARGET)
@echo Converting $<...
@$(PNG2BDC) $< $(OBJ)/temp.bdc
@$(FILE2STR) $(OBJ)/temp.bdc $@ font_$(basename $(notdir $<)) UINT8
@@ -745,3 +763,10 @@ $(OBJ)/%.o: $(SRC)/%.m | $(OSPREBUILD)
$(CC) $(CDEFS) $(COBJFLAGS) $(CCOMFLAGS) -c $< -o $@
endif
+
+
+#-------------------------------------------------
+# optional dependencies file
+#-------------------------------------------------
+
+-include depend.mak
diff --git a/src/build/build.mak b/src/build/build.mak
index 38e79b7434d..721346a3f6c 100644
--- a/src/build/build.mak
+++ b/src/build/build.mak
@@ -18,15 +18,29 @@ OBJDIRS += \
# set of build targets
#-------------------------------------------------
-FILE2STR = $(BUILDOUT)/file2str$(BUILD_EXE)
-PNG2BDC = $(BUILDOUT)/png2bdc$(BUILD_EXE)
-VERINFO = $(BUILDOUT)/verinfo$(BUILD_EXE)
+FILE2STR_TARGET = $(BUILDOUT)/file2str$(BUILD_EXE)
+MAKEDEP_TARGET = $(BUILDOUT)/makedep$(BUILD_EXE)
+PNG2BDC_TARGET = $(BUILDOUT)/png2bdc$(BUILD_EXE)
+VERINFO_TARGET = $(BUILDOUT)/verinfo$(BUILD_EXE)
+
+ifeq ($(TARGETOS),win32)
+FILE2STR = $(subst /,\,$(FILE2STR_TARGET))
+MAKEDEP = $(subst /,\,$(MAKEDEP_TARGET))
+PNG2BDC = $(subst /,\,$(PNG2BDC_TARGET))
+VERINFO = $(subst /,\,$(VERINFO_TARGET))
+else
+FILE2STR = $(FILE2STR_TARGET)
+MAKEDEP = $(MAKEDEP_TARGET)
+PNG2BDC = $(PNG2BDC_TARGET)
+VERINFO = $(VERINFO_TARGET)
+endif
ifneq ($(CROSS_BUILD),1)
BUILD += \
- $(FILE2STR) \
- $(PNG2BDC) \
- $(VERINFO) \
+ $(FILE2STR_TARGET) \
+ $(MAKEDEP_TARGET) \
+ $(PNG2BDC_TARGET) \
+ $(VERINFO_TARGET) \
@@ -37,7 +51,20 @@ BUILD += \
FILE2STROBJS = \
$(BUILDOBJ)/file2str.o \
-$(FILE2STR): $(FILE2STROBJS) $(LIBOCORE)
+$(FILE2STR_TARGET): $(FILE2STROBJS) $(LIBOCORE)
+ @echo Linking $@...
+ $(LD) $(LDFLAGS) $^ $(LIBS) -o $@
+
+
+
+#-------------------------------------------------
+# makedep
+#-------------------------------------------------
+
+MAKEDEPOBJS = \
+ $(BUILDOBJ)/makedep.o \
+
+$(MAKEDEP_TARGET): $(MAKEDEPOBJS) $(LIBUTIL) $(LIBOCORE) $(ZLIB)
@echo Linking $@...
$(LD) $(LDFLAGS) $^ $(LIBS) -o $@
@@ -50,7 +77,7 @@ $(FILE2STR): $(FILE2STROBJS) $(LIBOCORE)
PNG2BDCOBJS = \
$(BUILDOBJ)/png2bdc.o \
-$(PNG2BDC): $(PNG2BDCOBJS) $(LIBUTIL) $(LIBOCORE) $(ZLIB)
+$(PNG2BDC_TARGET): $(PNG2BDCOBJS) $(LIBUTIL) $(LIBOCORE) $(ZLIB)
@echo Linking $@...
$(LD) $(LDFLAGS) $^ $(LIBS) -o $@
@@ -63,7 +90,7 @@ $(PNG2BDC): $(PNG2BDCOBJS) $(LIBUTIL) $(LIBOCORE) $(ZLIB)
VERINFOOBJS = \
$(BUILDOBJ)/verinfo.o
-$(VERINFO): $(VERINFOOBJS) $(LIBOCORE)
+$(VERINFO_TARGET): $(VERINFOOBJS) $(LIBOCORE)
@echo Linking $@...
$(LD) $(LDFLAGS) $^ $(LIBS) -o $@
diff --git a/src/build/makedep.c b/src/build/makedep.c
new file mode 100644
index 00000000000..da7284c2618
--- /dev/null
+++ b/src/build/makedep.c
@@ -0,0 +1,542 @@
+/***************************************************************************
+
+ MAME source code dependency generator
+
+****************************************************************************
+
+ Copyright Aaron Giles
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name 'MAME' nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <zlib.h>
+#include "osdcore.h"
+#include "astring.h"
+#include "corefile.h"
+#include "tagmap.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define HASH_SIZE 193
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _include_path include_path;
+struct _include_path
+{
+ include_path * next;
+ const astring * path;
+};
+
+
+typedef struct _exclude_path exclude_path;
+struct _exclude_path
+{
+ exclude_path * next;
+ const astring * path;
+ int pathlen;
+ UINT8 recursive;
+};
+
+
+typedef struct _list_entry list_entry;
+struct _list_entry
+{
+ list_entry * next;
+ const astring * name;
+};
+
+
+typedef struct _file_entry file_entry;
+
+typedef struct _dependency dependency;
+struct _dependency
+{
+ dependency * next;
+ file_entry * file;
+};
+
+
+struct _file_entry
+{
+ astring * name;
+ dependency * deplist;
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+static include_path *incpaths;
+static exclude_path *excpaths;
+static tagmap *file_map;
+
+
+
+/***************************************************************************
+ PROTOTYPES
+***************************************************************************/
+
+/* core output functions */
+static int recurse_dir(int srcrootlen, const astring *srcdir);
+static file_entry *compute_dependencies(int srcrootlen, const astring *srcfile);
+
+/* path helpers */
+static astring *find_include_file(int srcrootlen, const astring *srcfile, const astring *filename);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/* core output functions */
+static int recurse_dir(int srcrootlen, const astring *srcdir);
+static file_entry *compute_dependencies(int srcrootlen, const astring *srcfile);
+
+/* path helpers */
+static astring *find_include_file(int srcrootlen, const astring *srcfile, const astring *filename);
+
+
+
+/***************************************************************************
+ MAIN
+***************************************************************************/
+
+/*-------------------------------------------------
+ main - main entry point
+-------------------------------------------------*/
+
+int main(int argc, char *argv[])
+{
+ include_path **incpathhead = &incpaths;
+ exclude_path **excpathhead = &excpaths;
+ astring *srcdir = NULL;
+ int unadorned = 0;
+ int result;
+ int argnum;
+
+ /* loop over arguments */
+ for (argnum = 1; argnum < argc; argnum++)
+ {
+ char *arg = argv[argnum];
+
+ /* include path? */
+ if (arg[0] == '-' && arg[1] == 'I')
+ {
+ *incpathhead = (include_path *)malloc(sizeof(**incpathhead));
+ if (*incpathhead != NULL)
+ {
+ (*incpathhead)->next = NULL;
+ (*incpathhead)->path = astring_replacechr(astring_dupc(&arg[2]), '/', PATH_SEPARATOR[0]);
+ incpathhead = &(*incpathhead)->next;
+ }
+ }
+
+ /* exclude path? */
+ else if (arg[0] == '-' && arg[1] == 'X')
+ {
+ *excpathhead = (exclude_path *)malloc(sizeof(**excpathhead));
+ if (*excpathhead != NULL)
+ {
+ astring *path;
+ (*excpathhead)->next = NULL;
+ path = astring_replacechr(astring_dupc(&arg[2]), PATH_SEPARATOR[0], '/');
+ (*excpathhead)->recursive = (astring_replacec(path, astring_len(path) - 4, "/...", "") != 0);
+ (*excpathhead)->path = path;
+ (*excpathhead)->pathlen = astring_len(path);
+ excpathhead = &(*excpathhead)->next;
+ }
+ }
+
+ /* other parameter */
+ else if (arg[0] != '-' && unadorned == 0)
+ {
+ srcdir = astring_replacechr(astring_dupc(arg), '/', PATH_SEPARATOR[0]);
+ unadorned++;
+ }
+ else
+ goto usage;
+ }
+
+ /* make sure we got 1 parameter */
+ if (srcdir == NULL)
+ goto usage;
+
+ /* create a tagmap for tracking files we've visited */
+ file_map = tagmap_alloc();
+
+ /* recurse over subdirectories */
+ result = recurse_dir(astring_len(srcdir), srcdir);
+
+ /* free source and destination directories */
+ tagmap_free(file_map);
+ astring_free(srcdir);
+ return result;
+
+usage:
+ fprintf(stderr, "Usage:\n%s <srcroot> [-Iincpath [-Iincpath [...]]]\n", argv[0]);
+ return 1;
+}
+
+
+
+/***************************************************************************
+ CORE OUTPUT FUNCTIONS
+***************************************************************************/
+
+static int compare_list_entries(const void *p1, const void *p2)
+{
+ const list_entry *entry1 = *(const list_entry **)p1;
+ const list_entry *entry2 = *(const list_entry **)p2;
+ return strcmp(astring_c(entry1->name), astring_c(entry2->name));
+}
+
+
+/*-------------------------------------------------
+ recurse_dependencies - recurse through the
+ dependencies found, adding the mto the tagmap
+ unless we already exist in the map
+-------------------------------------------------*/
+
+static void recurse_dependencies(file_entry *file, tagmap *map)
+{
+ int filelen = astring_len(file->name);
+ exclude_path *exclude;
+ dependency *dep;
+
+ /* skip if we're in an exclude path */
+ for (exclude = excpaths; exclude != NULL; exclude = exclude->next)
+ if (exclude->pathlen < filelen && strncmp(astring_c(file->name), astring_c(exclude->path), exclude->pathlen) == 0)
+ if (exclude->recursive || astring_chr(file->name, exclude->pathlen + 1, '/') == -1)
+ return;
+
+ /* attempt to add; if we get an error, we're already present */
+ if (tagmap_add(map, astring_c(file->name), file->name, FALSE) != TMERR_NONE)
+ return;
+
+ /* recurse the list from there */
+ for (dep = file->deplist; dep != NULL; dep = dep->next)
+ recurse_dependencies(dep->file, map);
+}
+
+
+/*-------------------------------------------------
+ recurse_dir - recurse through a directory
+-------------------------------------------------*/
+
+static int recurse_dir(int srcrootlen, const astring *srcdir)
+{
+ static const osd_dir_entry_type typelist[] = { ENTTYPE_DIR, ENTTYPE_FILE };
+ int result = 0;
+ int entindex;
+
+ /* iterate first over directories, then over files */
+ for (entindex = 0; entindex < ARRAY_LENGTH(typelist) && result == 0; entindex++)
+ {
+ osd_dir_entry_type entry_type = typelist[entindex];
+ const osd_directory_entry *entry;
+ list_entry **listarray = NULL;
+ list_entry *list = NULL;
+ list_entry *curlist;
+ osd_directory *dir;
+ int found = 0;
+
+ /* open the directory and iterate through it */
+ dir = osd_opendir(astring_c(srcdir));
+ if (dir == NULL)
+ {
+ result = 1;
+ goto error;
+ }
+
+ /* build up the list of files */
+ while ((entry = osd_readdir(dir)) != NULL)
+ if (entry->type == entry_type && entry->name[0] != '.')
+ {
+ list_entry *lentry = (list_entry *)malloc(sizeof(*lentry));
+ lentry->name = astring_dupc(entry->name);
+ lentry->next = list;
+ list = lentry;
+ found++;
+ }
+
+ /* close the directory */
+ osd_closedir(dir);
+
+ /* skip if nothing found */
+ if (found == 0)
+ continue;
+
+ /* allocate memory for sorting */
+ listarray = (list_entry **)malloc(sizeof(list_entry *) * found);
+ found = 0;
+ for (curlist = list; curlist != NULL; curlist = curlist->next)
+ listarray[found++] = curlist;
+
+ /* sort the list */
+ qsort(listarray, found, sizeof(listarray[0]), compare_list_entries);
+
+ /* rebuild the list */
+ list = NULL;
+ while (--found >= 0)
+ {
+ listarray[found]->next = list;
+ list = listarray[found];
+ }
+ free(listarray);
+
+ /* iterate through each file */
+ for (curlist = list; curlist != NULL && result == 0; curlist = curlist->next)
+ {
+ astring *srcfile;
+
+ /* build the source filename */
+ srcfile = astring_alloc();
+ astring_printf(srcfile, "%s%c%s", astring_c(srcdir), PATH_SEPARATOR[0], astring_c(curlist->name));
+
+ /* if we have a file, output it */
+ if (entry_type == ENTTYPE_FILE)
+ {
+ /* make sure we care, first */
+ if (core_filename_ends_with(astring_c(curlist->name), ".c"))
+ {
+ tagmap *depend_map = tagmap_alloc();
+ tagmap_entry *entry;
+ file_entry *file;
+ astring *target;
+ int taghash;
+
+ /* find dependencies */
+ file = compute_dependencies(srcrootlen, srcfile);
+ recurse_dependencies(file, depend_map);
+
+ /* convert the target from source to object (makes assumptions about rules) */
+ target = astring_dup(file->name);
+ astring_replacec(target, 0, "src/", "$(OBJ)/");
+ astring_replacec(target, 0, ".c", ".o");
+ printf("\n%s : \\\n", astring_c(target));
+
+ /* iterate over the hashed dependencies and output them as well */
+ for (taghash = 0; taghash < TAGMAP_HASH_SIZE; taghash++)
+ for (entry = depend_map->table[taghash]; entry != NULL; entry = entry->next)
+ printf("\t%s \\\n", astring_c((astring *)entry->object));
+
+ astring_free(target);
+ tagmap_free(depend_map);
+ }
+ }
+
+ /* if we have a directory, recurse */
+ else
+ result = recurse_dir(srcrootlen, srcfile);
+
+ /* free memory for the names */
+ astring_free(srcfile);
+ }
+
+ /* free all the allocated entries */
+ while (list != NULL)
+ {
+ list_entry *next = list->next;
+ astring_free((astring *)list->name);
+ free(list);
+ list = next;
+ }
+ }
+
+error:
+ return result;
+}
+
+
+/*-------------------------------------------------
+ output_file - output a file, converting to
+ HTML
+-------------------------------------------------*/
+
+static file_entry *compute_dependencies(int srcrootlen, const astring *srcfile)
+{
+ astring *normalfile;
+ UINT32 filelength;
+ file_entry *file;
+ char *filedata;
+ int found = 0;
+ int index;
+
+ /* see if we already have an entry */
+ normalfile = astring_dup(srcfile);
+ astring_replacechr(normalfile, PATH_SEPARATOR[0], '/');
+ file = (file_entry *)tagmap_find(file_map, astring_c(normalfile));
+ if (file != NULL)
+ return file;
+
+ /* create a new header entry */
+ file = (file_entry *)malloc(sizeof(*file));
+ file->deplist = NULL;
+ file->name = normalfile;
+ tagmap_add(file_map, astring_c(file->name), file, FALSE);
+
+ /* read the source file */
+ if (core_fload(astring_c(srcfile), (void **)&filedata, &filelength) != FILERR_NONE)
+ {
+ fprintf(stderr, "Unable to read file '%s'\n", astring_c(srcfile));
+ return file;
+ }
+
+ /* find the #include directives in this file */
+ for (index = 0; index < filelength; index++)
+ if (filedata[index] == '#' && strncmp(&filedata[index + 1], "include", 7) == 0)
+ {
+ astring *filename, *target;
+ int scan = index;
+ dependency *dep;
+ int start;
+
+ /* first make sure we're not commented or quoted */
+ for (scan = index; scan > 2 && filedata[scan] != 13 && filedata[scan] != 10; scan--)
+ if ((filedata[scan] == '/' && filedata[scan - 1] == '/') || filedata[scan] == '"')
+ break;
+ if (filedata[scan] != 13 && filedata[scan] != 10)
+ continue;
+
+ /* scan forward to find the quotes or bracket */
+ index += 7;
+ for (scan = index; scan < filelength && filedata[scan] != '<' && filedata[scan] != '"' && filedata[scan] != 13 && filedata[scan] != 10; scan++) ;
+
+ /* ignore if not found or if it's bracketed */
+ if (scan >= filelength || filedata[scan] != '"')
+ continue;
+ start = ++scan;
+
+ /* find the closing quote */
+ while (scan < filelength && filedata[scan] != '"')
+ scan++;
+ if (scan >= filelength)
+ continue;
+
+ /* find the include file */
+ filename = astring_dupch(&filedata[start], scan - start);
+ target = find_include_file(srcrootlen, srcfile, filename);
+
+ /* create a new dependency */
+ if (target != NULL)
+ {
+ dep = (dependency *)malloc(sizeof(*dep));
+ dep->next = file->deplist;
+ file->deplist = dep;
+ dep->file = compute_dependencies(srcrootlen, target);
+ astring_free(target);
+ }
+
+ astring_free(filename);
+ }
+
+ free(filedata);
+ return file;
+}
+
+
+
+/***************************************************************************
+ HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ find_include_file - find an include file
+-------------------------------------------------*/
+
+static astring *find_include_file(int srcrootlen, const astring *srcfile, const astring *filename)
+{
+ include_path *curpath;
+
+ /* iterate over include paths and find the file */
+ for (curpath = incpaths; curpath != NULL; curpath = curpath->next)
+ {
+ astring *srcincpath = astring_dup(curpath->path);
+ core_file *testfile;
+ int lastsepindex = 0;
+ int sepindex;
+
+ /* a '.' include path is specially treated */
+ if (astring_cmpc(curpath->path, ".") == 0)
+ astring_cpysubstr(srcincpath, srcfile, 0, astring_rchr(srcfile, 0, PATH_SEPARATOR[0]));
+
+ /* append the filename piecemeal to account for directories */
+ while ((sepindex = astring_chr(filename, lastsepindex, '/')) != -1)
+ {
+ astring *pathpart = astring_dupsubstr(filename, lastsepindex, sepindex - lastsepindex);
+
+ /* handle .. by removing a chunk from the incpath */
+ if (astring_cmpc(pathpart, "..") == 0)
+ {
+ int sepindex = astring_rchr(srcincpath, 0, PATH_SEPARATOR[0]);
+ if (sepindex != -1)
+ astring_substr(srcincpath, 0, sepindex);
+ }
+
+ /* otherwise, append a path separator and the pathpart */
+ else
+ astring_cat(astring_catc(srcincpath, PATH_SEPARATOR), pathpart);
+
+ /* advance past the previous index */
+ lastsepindex = sepindex + 1;
+
+ /* free the path part we extracted */
+ astring_free(pathpart);
+ }
+
+ /* now append the filename */
+ astring_catsubstr(astring_catc(srcincpath, PATH_SEPARATOR), filename, lastsepindex, -1);
+
+ /* see if we can open it */
+ if (core_fopen(astring_c(srcincpath), OPEN_FLAG_READ, &testfile) == FILERR_NONE)
+ {
+ /* close the file */
+ core_fclose(testfile);
+ return srcincpath;
+ }
+
+ /* free our include path */
+ astring_free(srcincpath);
+ }
+ return NULL;
+}