diff options
Diffstat (limited to 'src/tools/src2html.c')
-rw-r--r-- | src/tools/src2html.c | 860 |
1 files changed, 860 insertions, 0 deletions
diff --git a/src/tools/src2html.c b/src/tools/src2html.c new file mode 100644 index 00000000000..cce46c3e354 --- /dev/null +++ b/src/tools/src2html.c @@ -0,0 +1,860 @@ +/*************************************************************************** + + MAME source code to HTML converter + + Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team. + Visit http://mamedev.org for licensing and usage restrictions. + +***************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include "osdcore.h" +#include "astring.h" +#include "corefile.h" + + +/*************************************************************************** + CONSTANTS & DEFINES +***************************************************************************/ + +#define COMMENT_STYLE "color:#b30000" +#define STRING_STYLE "color:#666" +#define PREPROCESSOR_STYLE "color:#0000b3" +#define KEYWORD_STYLE "color:#0000b3" +#define MAMEWORD_STYLE "color:#7f007f" + + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +enum _file_type +{ + FILE_TYPE_INVALID, + FILE_TYPE_C, + FILE_TYPE_MAKE, + FILE_TYPE_XML, + FILE_TYPE_TEXT +}; +typedef enum _file_type file_type; + + +typedef struct _ext_to_type ext_to_type; +struct _ext_to_type +{ + const char * extension; + file_type type; +}; + + +typedef struct _token_entry token_entry; +struct _token_entry +{ + const char * token; + const char * color; +}; + + +typedef struct _include_path include_path; +struct _include_path +{ + include_path * next; + const astring * path; +}; + + + +/*************************************************************************** + GLOBAL VARIABLES +***************************************************************************/ + +static include_path *incpaths; +static include_path **incpathhead = &incpaths; + +static const ext_to_type extension_lookup[] = +{ + { ".c", FILE_TYPE_C }, + { ".h", FILE_TYPE_C }, + { ".mak", FILE_TYPE_MAKE }, + { "makefile", FILE_TYPE_MAKE }, + { ".lay", FILE_TYPE_XML }, + { ".txt", FILE_TYPE_TEXT }, +}; + + +static const token_entry dummy_token_table[] = +{ + { NULL, KEYWORD_STYLE } +}; + + +static const token_entry c_token_table[] = +{ + { "#define", PREPROCESSOR_STYLE }, + { "#elif", PREPROCESSOR_STYLE }, + { "#else", PREPROCESSOR_STYLE }, + { "#endif", PREPROCESSOR_STYLE }, + { "#error", PREPROCESSOR_STYLE }, + { "#if", PREPROCESSOR_STYLE }, + { "#ifdef", PREPROCESSOR_STYLE }, + { "#ifndef", PREPROCESSOR_STYLE }, + { "#include", PREPROCESSOR_STYLE }, + { "#line", PREPROCESSOR_STYLE }, + { "#pragma", PREPROCESSOR_STYLE }, + { "#undef", PREPROCESSOR_STYLE }, + + { "auto", KEYWORD_STYLE }, + { "break", KEYWORD_STYLE }, + { "case", KEYWORD_STYLE }, + { "char", KEYWORD_STYLE }, + { "const", KEYWORD_STYLE }, + { "continue", KEYWORD_STYLE }, + { "default", KEYWORD_STYLE }, + { "do", KEYWORD_STYLE }, + { "double", KEYWORD_STYLE }, + { "else", KEYWORD_STYLE }, + { "enum", KEYWORD_STYLE }, + { "extern", KEYWORD_STYLE }, + { "float", KEYWORD_STYLE }, + { "for", KEYWORD_STYLE }, + { "goto", KEYWORD_STYLE }, + { "if", KEYWORD_STYLE }, + { "int", KEYWORD_STYLE }, + { "long", KEYWORD_STYLE }, + { "register", KEYWORD_STYLE }, + { "return", KEYWORD_STYLE }, + { "short", KEYWORD_STYLE }, + { "signed", KEYWORD_STYLE }, + { "sizeof", KEYWORD_STYLE }, + { "static", KEYWORD_STYLE }, + { "struct", KEYWORD_STYLE }, + { "switch", KEYWORD_STYLE }, + { "typedef", KEYWORD_STYLE }, + { "union", KEYWORD_STYLE }, + { "unsigned", KEYWORD_STYLE }, + { "void", KEYWORD_STYLE }, + { "volatile", KEYWORD_STYLE }, + { "while", KEYWORD_STYLE }, + +/* + { "INLINE", MAMEWORD_STYLE }, + { "INT8", MAMEWORD_STYLE }, + { "UINT8", MAMEWORD_STYLE }, + { "INT16", MAMEWORD_STYLE }, + { "UINT16", MAMEWORD_STYLE }, + { "INT32", MAMEWORD_STYLE }, + { "UINT32", MAMEWORD_STYLE }, + { "INT64", MAMEWORD_STYLE }, + { "UINT64", MAMEWORD_STYLE }, + { "ARRAY_LENGTH", MAMEWORD_STYLE }, +*/ + { NULL, KEYWORD_STYLE } +}; + + + +/*************************************************************************** + PROTOTYPES +***************************************************************************/ + +/* core output functions */ +static int recurse_dir(int srcrootlen, int dstrootlen, const astring *srcdir, const astring *dstdir); +static int output_file(file_type type, int srcrootlen, int dstrootlen, const astring *srcfile, const astring *dstfile); + +/* HTML helpers */ +static core_file *create_file_and_output_header(const astring *filename, const char *title, const char *subtitle); +static void output_footer_and_close_file(core_file *file); + +/* path helpers */ +static const astring *normalized_subpath(const astring *path, int start); +static void output_path_as_links(core_file *file, const astring *path, int end_is_directory); +static astring *find_include_file(int srcrootlen, int dstrootlen, const astring *srcfile, const astring *dstfile, const astring *filename); + + + +/*************************************************************************** + MAIN +***************************************************************************/ + +/*------------------------------------------------- + main - main entry point +-------------------------------------------------*/ + +int main(int argc, char *argv[]) +{ + astring *srcdir = NULL, *dstdir = 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 = malloc(sizeof(**incpathhead)); + if (*incpathhead != NULL) + { + (*incpathhead)->next = NULL; + (*incpathhead)->path = astring_replacechr(astring_dupc(&arg[2]), '/', PATH_SEPARATOR[0]); + incpathhead = &(*incpathhead)->next; + } + } + + /* other parameter */ + else if (arg[0] != '-' && unadorned == 0) + { + srcdir = astring_dupc(arg); + unadorned++; + } + else if (arg[0] != '-' && unadorned == 1) + { + dstdir = astring_dupc(arg); + unadorned++; + } + else + goto usage; + } + + /* make sure we got 2 parameters */ + if (srcdir == NULL || dstdir == NULL) + goto usage; + + /* recurse over subdirectories */ + result = recurse_dir(astring_len(srcdir), astring_len(dstdir), srcdir, dstdir); + + /* free source and destination directories */ + astring_free(srcdir); + astring_free(dstdir); + return result; + +usage: + fprintf(stderr, "Usage:\n%s <srcroot> <destroot> [-Iincpath [-Iincpath [...]]]\n", argv[0]); + return 1; +} + + + +/*************************************************************************** + CORE OUTPUT FUNCTIONS +***************************************************************************/ + +/*------------------------------------------------- + recurse_dir - recurse through a directory +-------------------------------------------------*/ + +static int recurse_dir(int srcrootlen, int dstrootlen, const astring *srcdir, const astring *dstdir) +{ + static const osd_dir_entry_type typelist[] = { ENTTYPE_DIR, ENTTYPE_FILE }; + const astring *srcdir_subpath; + core_file *indexfile = NULL; + astring *indexname; + int result = 0; + int entindex; + + /* extract a normalized subpath */ + srcdir_subpath = normalized_subpath(srcdir, srcrootlen + 1); + if (srcdir_subpath == NULL) + return 1; + + /* create an index file */ + indexname = astring_alloc(); + astring_printf(indexname, "%s%c%s", astring_c(dstdir), PATH_SEPARATOR[0], "index.html"); + indexfile = create_file_and_output_header(indexname, "MAME Source Code", astring_c(srcdir_subpath)); + astring_free(indexname); + + /* output the directory navigation */ + core_fprintf(indexfile, "<h3>Viewing Directory: "); + output_path_as_links(indexfile, srcdir_subpath, TRUE); + core_fprintf(indexfile, "</h3>"); + astring_free((astring *)srcdir_subpath); + + /* 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; + 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; + } + + /* iterate through each file */ + while ((entry = osd_readdir(dir)) != NULL && result == 0) + if (entry->type == entry_type && entry->name[0] != '.') + { + astring *srcfile, *dstfile; + + /* add a header */ + if (++found == 1) + core_fprintf(indexfile, "\t<h2>%s</h2>\n\t<ul>\n", (entry_type == ENTTYPE_DIR) ? "Directories" : "Files"); + + /* build the source filename */ + srcfile = astring_alloc(); + astring_printf(srcfile, "%s%c%s", astring_c(srcdir), PATH_SEPARATOR[0], entry->name); + + /* if we have a file, output it */ + dstfile = astring_alloc(); + if (entry->type == ENTTYPE_FILE) + { + file_type type = FILE_TYPE_INVALID; + int extnum; + + /* make sure we care, first */ + for (extnum = 0; extnum < ARRAY_LENGTH(extension_lookup); extnum++) + if (core_filename_ends_with(entry->name, extension_lookup[extnum].extension)) + { + type = extension_lookup[extnum].type; + break; + } + + /* if we got a valid file, process it */ + if (type != FILE_TYPE_INVALID) + { + astring_printf(dstfile, "%s%c%s.html", astring_c(dstdir), PATH_SEPARATOR[0], entry->name); + if (indexfile != NULL) + core_fprintf(indexfile, "\t<li><a href=\"%s.html\">%s</a></li>\n", entry->name, entry->name); + result = output_file(type, srcrootlen, dstrootlen, srcfile, dstfile); + } + } + + /* if we have a directory, recurse */ + else + { + astring_printf(dstfile, "%s%c%s", astring_c(dstdir), PATH_SEPARATOR[0], entry->name); + if (indexfile != NULL) + core_fprintf(indexfile, "\t<li><a href=\"%s/index.html\">%s/</a></li>\n", entry->name, entry->name); + result = recurse_dir(srcrootlen, dstrootlen, srcfile, dstfile); + } + + /* free memory for the names */ + astring_free(srcfile); + astring_free(dstfile); + } + + /* close the list if we found some stuff */ + if (found > 0) + core_fprintf(indexfile, "\t</ul>\n"); + + /* close the directory */ + osd_closedir(dir); + } + +error: + if (indexfile != NULL) + output_footer_and_close_file(indexfile); + return result; +} + + +/*------------------------------------------------- + output_file - output a file, converting to + HTML +-------------------------------------------------*/ + +static int output_file(file_type type, int srcrootlen, int dstrootlen, const astring *srcfile, const astring *dstfile) +{ + const char *comment_start, *comment_end, *comment_inline, *token_chars; + const char *comment_start_esc, *comment_end_esc, *comment_inline_esc; + const token_entry *token_table; + const astring *srcfile_subpath; + char srcline[4096], *srcptr; + int in_comment = FALSE; + UINT8 is_token[256]; + int color_quotes; + core_file *src; + core_file *dst; + int toknum; + + /* extract a normalized subpath */ + srcfile_subpath = normalized_subpath(srcfile, srcrootlen + 1); + if (srcfile_subpath == NULL) + return 1; + + fprintf(stderr, "Processing %s\n", astring_c(srcfile_subpath)); + + /* set some defaults */ + color_quotes = FALSE; + comment_start = comment_start_esc = ""; + comment_end = comment_end_esc = ""; + comment_inline = comment_inline_esc = ""; + token_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_#"; + token_table = dummy_token_table; + + /* based on the file type, set the comment info */ + switch (type) + { + case FILE_TYPE_C: + color_quotes = TRUE; + comment_start = comment_start_esc = "/*"; + comment_end = comment_end_esc = "*/"; + comment_inline = comment_inline_esc = "//"; + token_table = c_token_table; + break; + + case FILE_TYPE_MAKE: + color_quotes = TRUE; + comment_inline = comment_inline_esc = "#"; + break; + + case FILE_TYPE_XML: + color_quotes = TRUE; + comment_start = "<!--"; + comment_start_esc = "<!--"; + comment_end = "-->"; + comment_end_esc = "-->"; + break; + + default: + case FILE_TYPE_TEXT: + break; + } + + /* make the token lookup table */ + memset(is_token, 0, sizeof(is_token)); + for (toknum = 0; token_chars[toknum] != 0; toknum++) + is_token[(UINT8)token_chars[toknum]] = TRUE; + + /* open the source file */ + if (core_fopen(astring_c(srcfile), OPEN_FLAG_READ, &src) != FILERR_NONE) + { + fprintf(stderr, "Unable to read file '%s'\n", astring_c(srcfile)); + return 1; + } + + /* open the output file */ + dst = create_file_and_output_header(dstfile, "MAME Source Code", astring_c(srcfile_subpath)); + if (dst == NULL) + { + fprintf(stderr, "Unable to write file '%s'\n", astring_c(dstfile)); + core_fclose(src); + return 1; + } + + /* output the directory navigation */ + core_fprintf(dst, "<h3>Viewing File: "); + output_path_as_links(dst, srcfile_subpath, FALSE); + core_fprintf(dst, "</h3>"); + astring_free((astring *)srcfile_subpath); + + /* start with some tags */ + core_fprintf(dst, "\t<pre style=\"font-family:'Courier New','Courier',monospace; font-size:12px;\">\n"); + + /* iterate over lines in the source file */ + while (core_fgets(srcline, ARRAY_LENGTH(srcline), src) != NULL) + { + char dstline[4096], *dstptr = dstline; + int in_inline_comment = FALSE; + int last_token_was_include = FALSE; + int last_was_token = FALSE; + int quotes_are_linked = FALSE; + char in_quotes = 0; + int curcol = 0; + + /* iterate over characters in the source line */ + for (srcptr = srcline; *srcptr != 0; ) + { + UINT8 ch = *srcptr++; + + /* track whether or not we are within an extended (C-style) comment */ + if (!in_quotes && !in_inline_comment) + { + if (!in_comment && ch == comment_start[0] && strncmp(srcptr - 1, comment_start, strlen(comment_start)) == 0) + { + dstptr += sprintf(dstptr, "<span style=\"" COMMENT_STYLE "\">%s", comment_start_esc); + curcol += strlen(comment_start); + srcptr += strlen(comment_start) - 1; + ch = 0; + in_comment = TRUE; + } + else if (in_comment && ch == comment_end[0] && strncmp(srcptr - 1, comment_end, strlen(comment_end)) == 0) + { + dstptr += sprintf(dstptr, "%s</span>", comment_end_esc); + curcol += strlen(comment_end); + srcptr += strlen(comment_end) - 1; + ch = 0; + in_comment = FALSE; + } + } + + /* track whether or not we are within an inline (C++-style) comment */ + if (!in_quotes && !in_comment && !in_inline_comment && ch == comment_inline[0] && strncmp(srcptr - 1, comment_inline, strlen(comment_inline)) == 0) + { + dstptr += sprintf(dstptr, "<span style=\"" COMMENT_STYLE "\">%s", comment_inline_esc); + curcol += strlen(comment_inline); + srcptr += strlen(comment_inline) - 1; + ch = 0; + in_inline_comment = TRUE; + } + + /* if this is the start of a new token, see if we want to color it */ + if (!in_quotes && !in_comment && !in_inline_comment && !last_was_token && is_token[ch]) + { + const token_entry *curtoken; + char *temp = srcptr; + int toklength; + + /* find the end of the token */ + while (*temp != 0 && is_token[(UINT8)*temp]) + temp++; + toklength = temp - (srcptr - 1); + + /* scan the token table */ + last_token_was_include = FALSE; + for (curtoken = token_table; curtoken->token != NULL; curtoken++) + if (strncmp(srcptr - 1, curtoken->token, toklength) == 0 && strlen(curtoken->token) == toklength) + { + dstptr += sprintf(dstptr, "<span style=\"%s\">%s</span>", curtoken->color, curtoken->token); + curcol += strlen(curtoken->token); + srcptr += strlen(curtoken->token) - 1; + ch = 0; + + /* look for include tokens specially */ + if (type == FILE_TYPE_C && strcmp(curtoken->token, "#include") == 0) + last_token_was_include = TRUE; + break; + } + } + last_was_token = is_token[ch]; + + /* if we hit a tab, expand it */ + if (ch == 0x09) + { + /* compute how many spaces */ + int spaces = 4 - curcol % 4; + while (spaces--) + { + *dstptr++ = ' '; + curcol++; + } + } + + /* otherwise, copy the source character */ + else if (ch != 0x0a && ch != 0x0d && ch != 0) + { + /* track opening quotes */ + if (!in_comment && !in_inline_comment && !in_quotes && (ch == '"' || ch == '\'')) + { + if (color_quotes) + dstptr += sprintf(dstptr, "<span style=\"" STRING_STYLE "\">%c", ch); + else + *dstptr++ = ch; + in_quotes = ch; + + /* handle includes */ + if (last_token_was_include) + { + char *endquote = strchr(srcptr, ch); + if (endquote != NULL) + { + astring *filename = astring_dupch(srcptr, endquote - srcptr); + astring *target = find_include_file(srcrootlen, dstrootlen, srcfile, dstfile, filename); + if (target != NULL) + { + dstptr += sprintf(dstptr, "<a href=\"%s\">", astring_c(target)); + quotes_are_linked = TRUE; + astring_free(target); + } + astring_free(filename); + } + } + } + + /* track closing quotes */ + else if (!in_comment && !in_inline_comment && in_quotes && ch == in_quotes && (type != FILE_TYPE_C || srcptr[-2] != '\\' || srcptr[-3] == '\\')) + { + if (quotes_are_linked) + dstptr += sprintf(dstptr, "</a>"); + if (color_quotes) + dstptr += sprintf(dstptr, "%c</span>", ch); + else + *dstptr++ = ch; + in_quotes = 0; + quotes_are_linked = FALSE; + } + + /* else just output the current character */ + else if (ch == '&') + dstptr += sprintf(dstptr, "&"); + else if (ch == '<') + dstptr += sprintf(dstptr, "<"); + else if (ch == '>') + dstptr += sprintf(dstptr, ">"); + else + *dstptr++ = ch; + curcol++; + } + } + + /* finish inline comments */ + if (in_inline_comment) + { + dstptr += sprintf(dstptr, "</span>"); + in_inline_comment = FALSE; + } + + /* append a break and move on */ + dstptr += sprintf(dstptr, "\n"); + core_fputs(dst, dstline); + } + + /* close tags */ + core_fprintf(dst, "\t</pre>\n"); + + /* close the file */ + output_footer_and_close_file(dst); + core_fclose(src); + return 0; +} + + + +/*************************************************************************** + HTML OUTPUT HELPERS +***************************************************************************/ + +/*------------------------------------------------- + create_file_and_output_header - create a new + HTML file with a standard header +-------------------------------------------------*/ + +static core_file *create_file_and_output_header(const astring *filename, const char *title, const char *subtitle) +{ + core_file *file; + + /* create the indexfile */ + if (core_fopen(astring_c(filename), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS | OPEN_FLAG_NO_BOM, &file) != FILERR_NONE) + return NULL; + + /* print a header */ + core_fprintf(file, + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" + "\n" + "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" + "<head>\n" + "\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n" + "\t<title>%s</title>\n" + "\t<link rel=\"stylesheet\" href=\"http://mamedev.org/styles-site.css\" type=\"text/css\" />\n" + "</head>\n" + "\n" + "<body>\n" + "\t<div id=\"outer\">\n" + "\n" + "\t<div id=\"banner\">\n" + "\t<h1>%s</h1>\n" + "\t<h2>%s</h2>\n" + "\t</div>\n" + "\n" + "\t<div id=\"left\">\n" + "\t<div class=\"sidebar\">\n" + "\t<!--#include virtual=\"/links.txt\" -->\n" + "\t</div>\n" + "\t</div>\n" + "\n" + "\t<div id=\"center\">\n" + "\t<div class=\"content\">\n" + "\n", + title, title, (subtitle == NULL) ? " " : subtitle + ); + + /* return the file */ + return file; +} + + +/*------------------------------------------------- + output_footer_and_close_file - write a + standard footer to an HTML file and close it +-------------------------------------------------*/ + +static void output_footer_and_close_file(core_file *file) +{ + core_fprintf(file, + "\n" + "\t</div>\n" + "\t</div>\n" + "\t</div>\n" + "</body>" + "\n" + "</html>\n" + ); + core_fclose(file); +} + + + +/*************************************************************************** + HTML OUTPUT HELPERS +***************************************************************************/ + +/*------------------------------------------------- + normalized_subpath - normalize a path to + forward slashes and extract a subpath +-------------------------------------------------*/ + +static const astring *normalized_subpath(const astring *path, int start) +{ + astring *result = astring_dupsubstr(path, start, -1); + if (result != NULL) + astring_replacechr(result, PATH_SEPARATOR[0], '/'); + return result; +} + + +/*------------------------------------------------- + output_path_as_links - output a path as a + series of links +-------------------------------------------------*/ + +static void output_path_as_links(core_file *file, const astring *path, int end_is_directory) +{ + astring *substr = astring_alloc(); + int srcdepth, curdepth, depth; + int slashindex, lastslash; + + /* first count how deep we are */ + srcdepth = 0; + for (slashindex = astring_chr(path, 0, '/'); slashindex != -1; slashindex = astring_chr(path, slashindex + 1, '/')) + srcdepth++; + if (end_is_directory) + srcdepth++; + + /* output a link to the root */ + core_fprintf(file, "<a href=\""); + for (depth = 0; depth < srcdepth; depth++) + core_fprintf(file, "../"); + core_fprintf(file, "index.html\"><root></a>/"); + + /* now output links to each path up the chain */ + curdepth = 0; + lastslash = 0; + for (slashindex = astring_chr(path, lastslash, '/'); slashindex != -1; slashindex = astring_chr(path, lastslash, '/')) + { + astring_cpysubstr(substr, path, lastslash, slashindex - lastslash); + + curdepth++; + core_fprintf(file, "<a href=\""); + for (depth = curdepth; depth < srcdepth; depth++) + core_fprintf(file, "../"); + core_fprintf(file, "index.html\">%s</a>/", astring_c(substr)); + + lastslash = slashindex + 1; + } + + /* and a final link to the current directory */ + astring_cpysubstr(substr, path, lastslash, -1); + if (end_is_directory) + core_fprintf(file, "<a href=\"index.html\">%s</a>", astring_c(substr)); + else + core_fprintf(file, "<a href=\"%s.html\">%s</a>", astring_c(substr), astring_c(substr)); + + astring_free(substr); +} + + +/*------------------------------------------------- + find_include_file - find an include file +-------------------------------------------------*/ + +static astring *find_include_file(int srcrootlen, int dstrootlen, const astring *srcfile, const astring *dstfile, 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_cat(astring_dupsubstr(srcfile, 0, srcrootlen + 1), 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) + { + 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) + { + astring *tempfile = astring_alloc(); + astring *tempinc = astring_alloc(); + + /* close the file */ + core_fclose(testfile); + + /* find the longest matching directory substring between the include and source file */ + lastsepindex = 0; + while ((sepindex = astring_chr(srcincpath, lastsepindex, PATH_SEPARATOR[0])) != -1) + { + /* get substrings up to the current directory */ + astring_cpysubstr(tempfile, srcfile, 0, sepindex); + astring_cpysubstr(tempinc, srcincpath, 0, sepindex); + + /* if we don't match, stop */ + if (astring_cmp(tempfile, tempinc) != 0) + break; + lastsepindex = sepindex + 1; + } + + /* chop off the common parts of the paths */ + astring_cpysubstr(tempfile, srcfile, lastsepindex, -1); + astring_replacechr(astring_substr(srcincpath, lastsepindex, -1), PATH_SEPARATOR[0], '/'); + + /* for each directory left in the filename, we need to prepend a "../" */ + while ((sepindex = astring_chr(tempfile, 0, PATH_SEPARATOR[0])) != -1) + { + astring_substr(tempfile, sepindex + 1, -1); + astring_insc(srcincpath, 0, "../"); + } + astring_catc(srcincpath, ".html"); + + /* free the strings and return the include path */ + astring_free(tempfile); + astring_free(tempinc); + return srcincpath; + } + + /* free our include path */ + astring_free(srcincpath); + } + return NULL; +} |