static int output_file(file_type type, int srcrootlen, int dstrootlen, std::string &srcfile, std::string &dstfile, bool link_to_file, std::string &tempheader, std::string &tempfooter) { // extract a normalized subpath std::string srcfile_subpath; normalized_subpath(srcfile_subpath, srcfile, srcrootlen + 1); fprintf(stderr, "Processing %s\n", srcfile_subpath.c_str()); // set some defaults bool color_quotes = false; const char *comment_start = ""; const char *comment_start_esc = ""; const char *comment_end = ""; const char *comment_end_esc = ""; const char *comment_inline = ""; const char *comment_inline_esc = ""; const char *token_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_#"; const token_entry *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 bool is_token[256]; memset(is_token, 0, sizeof(is_token)); for (int toknum = 0; token_chars[toknum] != 0; toknum++) is_token[(uint8_t)token_chars[toknum]] = true; // open the source file util::core_file::ptr src; if (util::core_file::open(srcfile, OPEN_FLAG_READ, src) != osd_file::error::NONE) { fprintf(stderr, "Unable to read file '%s'\n", srcfile.c_str()); return 1; } // open the output file util::core_file::ptr dst = create_file_and_output_header(dstfile, tempheader, srcfile_subpath); if (dst == nullptr) { fprintf(stderr, "Unable to write file '%s'\n", dstfile.c_str()); return 1; } // output the directory navigation dst->printf("<h3>Viewing File: "); output_path_as_links(*dst, srcfile_subpath, false, link_to_file); dst->printf("</h3>"); // start with some tags dst->printf("\t<pre class=\"source\">\n"); // iterate over lines in the source file int linenum = 1; bool in_comment = false; char srcline[4096]; std::ostringstream dstline; while (src->gets(srcline, ARRAY_LENGTH(srcline)) != nullptr) { // start with the line number dstline.str(""); util::stream_format(dstline, "<span class=\"linenum\">%5d</span> ", linenum++); // iterate over characters in the source line bool escape = false; bool in_quotes = false; bool in_inline_comment = false; bool last_token_was_include = false; bool last_was_token = false; bool quotes_are_linked = false; uint8_t curquote = 0; int curcol = 0; for (char *srcptr = srcline; *srcptr != 0; ) { uint8_t 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) { util::stream_format(dstline, "<span class=\"comment\">%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) { util::stream_format(dstline, "%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) { util::stream_format(dstline, "<span class=\"comment\">%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_t)*temp]) temp++; toklength = temp - (srcptr - 1); // scan the token table last_token_was_include = false; for (curtoken = token_table; curtoken->token != nullptr; curtoken++) if (strncmp(srcptr - 1, curtoken->token, toklength) == 0 && strlen(curtoken->token) == toklength) { util::stream_format(dstline, "<span class=\"%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--) { dstline.put(' '); 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) util::stream_format(dstline, "<span class=\"string\">%c", ch); else dstline.put(ch); in_quotes = true; curquote = ch; // handle includes if (last_token_was_include) { char *endquote = strchr(srcptr, ch); if (endquote != nullptr) { std::string filename(srcptr, endquote - srcptr); std::string target; if (find_include_file(target, srcrootlen, dstrootlen, srcfile, dstfile, filename)) { util::stream_format(dstline, "<a href=\"%s\">", target.c_str()); quotes_are_linked = true; } } } } // track closing quotes else if (!in_comment && !in_inline_comment && in_quotes && (ch == curquote) && !escape) { if (quotes_are_linked) dstline << "</a>"; if (color_quotes) util::stream_format(dstline, "%c</span>", ch); else dstline.put(ch); in_quotes = false; curquote = 0; quotes_are_linked = false; } // else just output the current character else if (ch == '&') dstline << "&"; else if (ch == '<') dstline << "<"; else if (ch == '>') dstline << ">"; else dstline.put(ch); curcol++; } // Update escape state if (in_quotes) escape = (ch == '\\' && type == FILE_TYPE_C) ? !escape : false; } // finish inline comments if (in_inline_comment) { dstline << "</span>"; in_inline_comment = false; } // append a break and move on dstline.put('\n'); dst->puts(dstline.str().c_str()); } // close tags dst->printf("\t</pre>\n"); // close the file output_footer_and_close_file(std::move(dst), tempfooter, srcfile_subpath); return 0; }
static void create_linked_file(std::string &dirname, const summary_file *curfile, const summary_file *prevfile, const summary_file *nextfile, const char *pngfile, std::string &tempheader, std::string &tempfooter) { std::string linkname; std::string filename; std::string title; util::core_file::ptr linkfile; int listnum; /* create the filename */ filename = string_format("%s.html", curfile->name); /* output header */ title = string_format("%s Regressions (%s)", curfile->name, curfile->source); linkname = string_format("%s" PATH_SEPARATOR "%s", dirname.c_str(), filename.c_str()); linkfile = create_file_and_output_header(linkname, tempheader, title); if (linkfile == nullptr) { fprintf(stderr, "Error creating file '%s'\n", filename.c_str()); return; } /* link to the previous/next entries */ linkfile->printf("\t<p>\n"); linkfile->printf("\t<table width=\"100%%\">\n"); linkfile->printf("\t\t<td align=\"left\" width=\"40%%\" style=\"border:none\">"); if (prevfile != nullptr) linkfile->printf("<a href=\"%s.html\"><< %s (%s)</a>", prevfile->name, prevfile->name, prevfile->source); linkfile->printf("</td>\n"); linkfile->printf("\t\t<td align=\"center\" width=\"20%%\" style=\"border:none\"><a href=\"index.html\">Home</a></td>\n"); linkfile->printf("\t\t<td align=\"right\" width=\"40%%\" style=\"border:none\">"); if (nextfile != nullptr) linkfile->printf("<a href=\"%s.html\">%s (%s) >></a>", nextfile->name, nextfile->name, nextfile->source); linkfile->printf("</td>\n"); linkfile->printf("\t</table>\n"); linkfile->printf("\t</p>\n"); /* output data for each one */ for (listnum = 0; listnum < list_count; listnum++) { int imageindex = -1; /* generate the HTML */ linkfile->printf("\n\t<h2>%s</h2>\n", lists[listnum].version); linkfile->printf("\t<p>\n"); linkfile->printf("\t<b>Status:</b> %s\n", status_text[curfile->status[listnum]]); if (pngfile != nullptr) imageindex = get_unique_index(curfile, listnum); if (imageindex != -1) linkfile->printf(" [%d]", imageindex); linkfile->printf("\t</p>\n"); if (curfile->text[listnum].length() != 0) { linkfile->printf("\t<p>\n"); linkfile->printf("\t<b>Errors:</b>\n"); linkfile->printf("\t<pre>%s</pre>\n", curfile->text[listnum].c_str()); linkfile->printf("\t</p>\n"); } } /* output link to the image */ if (pngfile != nullptr) { linkfile->printf("\n\t<h2>Screenshot Comparisons</h2>\n"); linkfile->printf("\t<p>\n"); linkfile->printf("\t<img src=\"%s\" />\n", pngfile); linkfile->printf("\t</p>\n"); } /* output footer */ output_footer_and_close_file(std::move(linkfile), tempfooter, title); }
static int recurse_dir(int srcrootlen, int dstrootlen, std::string &srcdir, std::string &dstdir, std::string &tempheader, std::string &tempfooter) { static const osd::directory::entry::entry_type typelist[] = { osd::directory::entry::entry_type::DIR, osd::directory::entry::entry_type::FILE }; // extract a normalized subpath std::string srcdir_subpath; normalized_subpath(srcdir_subpath, srcdir, srcrootlen + 1); // create an index file std::string indexname; indexname = string_format("%s%c%s", dstdir.c_str(), PATH_SEPARATOR[0], "index.html"); util::core_file::ptr indexfile = create_file_and_output_header(indexname, tempheader, srcdir_subpath); // output the directory navigation indexfile->printf("<h3>Viewing Directory: "); output_path_as_links(*indexfile, srcdir_subpath, true, false); indexfile->printf("</h3>"); // iterate first over directories, then over files int result = 0; for (int entindex = 0; entindex < ARRAY_LENGTH(typelist) && result == 0; entindex++) { auto entry_type = typelist[entindex]; // open the directory and iterate through it auto dir = osd::directory::open(srcdir.c_str()); if (dir == nullptr) { result = 1; break; } // build up the list of files const osd::directory::entry *entry; int found = 0; list_entry *list = nullptr; while ((entry = dir->read()) != nullptr) if (entry->type == entry_type && entry->name[0] != '.') { auto lentry = new list_entry; lentry->name.assign(entry->name); lentry->next = list; list = lentry; found++; } // close the directory dir.reset(); // skip if nothing found if (found == 0) continue; // allocate memory for sorting auto listarray = new list_entry *[found]; found = 0; for (list_entry *curlist = list; curlist != nullptr; curlist = curlist->next) listarray[found++] = curlist; // sort the list qsort(listarray, found, sizeof(listarray[0]), compare_list_entries); // rebuild the list list = nullptr; while (--found >= 0) { listarray[found]->next = list; list = listarray[found]; } delete[] listarray; // iterate through each file for (list_entry *curlist = list; curlist != nullptr && result == 0; curlist = curlist->next) { // add a header if (curlist == list) indexfile->printf("\t<h2>%s</h2>\n\t<ul>\n", (entry_type == osd::directory::entry::entry_type::DIR) ? "Directories" : "Files"); // build the source filename std::string srcfile; srcfile = string_format("%s%c%s", srcdir.c_str(), PATH_SEPARATOR[0], curlist->name.c_str()); // if we have a file, output it std::string dstfile; if (entry_type == osd::directory::entry::entry_type::FILE) { // make sure we care, first file_type type = FILE_TYPE_INVALID; for (auto & elem : extension_lookup) if (core_filename_ends_with(curlist->name, elem.extension)) { type = elem.type; break; } // if we got a valid file, process it if (type != FILE_TYPE_INVALID) { dstfile = string_format("%s%c%s.html", dstdir.c_str(), PATH_SEPARATOR[0], curlist->name.c_str()); if (indexfile != nullptr) indexfile->printf("\t<li><a href=\"%s.html\">%s</a></li>\n", curlist->name.c_str(), curlist->name.c_str()); result = output_file(type, srcrootlen, dstrootlen, srcfile, dstfile, srcdir.compare(dstdir) == 0, tempheader, tempfooter); } } // if we have a directory, recurse else { dstfile = string_format("%s%c%s", dstdir.c_str(), PATH_SEPARATOR[0], curlist->name.c_str()); if (indexfile != nullptr) indexfile->printf("\t<li><a href=\"%s/index.html\">%s/</a></li>\n", curlist->name.c_str(), curlist->name.c_str()); result = recurse_dir(srcrootlen, dstrootlen, srcfile, dstfile, tempheader, tempfooter); } } // close the list if we found some stuff if (list != nullptr) indexfile->printf("\t</ul>\n"); // free all the allocated entries while (list != nullptr) { list_entry *next = list->next; delete list; list = next; } } if (indexfile != nullptr) output_footer_and_close_file(std::move(indexfile), tempfooter, srcdir_subpath); return result; }
static void output_report(std::string &dirname, std::string &tempheader, std::string &tempfooter, summary_file *filelist) { summary_file *buckethead[BUCKET_COUNT], **buckettailptr[BUCKET_COUNT]; summary_file *curfile; std::string title("MAME Regressions"); std::string tempname; int listnum, bucknum; util::core_file::ptr indexfile; int count = 0, total; /* initialize the lists */ for (bucknum = 0; bucknum < BUCKET_COUNT; bucknum++) { buckethead[bucknum] = nullptr; buckettailptr[bucknum] = &buckethead[bucknum]; } /* compute the total number of files */ total = 0; for (curfile = filelist; curfile != nullptr; curfile = curfile->next) total++; /* first bucketize the games */ for (curfile = filelist; curfile != nullptr; curfile = curfile->next) { int statcount[STATUS_COUNT] = { 0 }; int bucket = BUCKET_UNKNOWN; int unique_codes = 0; int first_valid; /* print status */ if (++count % 100 == 0) fprintf(stderr, "Processing file %d/%d\n", count, total); /* find the first valid entry */ for (first_valid = 0; curfile->status[first_valid] == STATUS_NOT_PRESENT; first_valid++) ; /* do we need to output anything? */ for (listnum = first_valid; listnum < list_count; listnum++) if (statcount[curfile->status[listnum]]++ == 0) unique_codes++; /* were we consistent? */ if (unique_codes == 1) { /* were we consistently ok? */ if (curfile->status[first_valid] == STATUS_SUCCESS) bucket = compare_screenshots(curfile); /* must have been consistently erroring */ else bucket = BUCKET_CONSISTENT_ERROR; } /* ok, we're not consistent; could be a number of things */ else { /* were we ok at the start and end but not in the middle? */ if (curfile->status[first_valid] == STATUS_SUCCESS && curfile->status[list_count - 1] == STATUS_SUCCESS) bucket = BUCKET_GOOD_BUT_CHANGED; /* did we go from good to bad? */ else if (curfile->status[first_valid] == STATUS_SUCCESS) bucket = BUCKET_REGRESSED; /* did we go from bad to good? */ else if (curfile->status[list_count - 1] == STATUS_SUCCESS) bucket = BUCKET_IMPROVED; /* must have had multiple errors */ else bucket = BUCKET_MULTI_ERROR; } /* add us to the appropriate list */ *buckettailptr[bucket] = curfile; buckettailptr[bucket] = &curfile->next; } /* terminate all the lists */ for (bucknum = 0; bucknum < BUCKET_COUNT; bucknum++) *buckettailptr[bucknum] = nullptr; /* output header */ tempname = string_format("%s" PATH_SEPARATOR "%s", dirname.c_str(), "index.html"); indexfile = create_file_and_output_header(tempname, tempheader, title); if (!indexfile) { fprintf(stderr, "Error creating file '%s'\n", tempname.c_str()); return; } /* iterate over buckets and output them */ for (bucknum = 0; bucknum < ARRAY_LENGTH(bucket_output_order); bucknum++) { int curbucket = bucket_output_order[bucknum]; if (buckethead[curbucket] != nullptr) { fprintf(stderr, "Outputting bucket: %s\n", bucket_name[curbucket]); append_driver_list_table(bucket_name[curbucket], dirname, *indexfile, buckethead[curbucket], tempheader, tempfooter); } } /* output footer */ output_footer_and_close_file(std::move(indexfile), tempfooter, title); }
static int recurse_dir(int srcrootlen, int dstrootlen, astring &srcdir, astring &dstdir, astring &tempheader, astring &tempfooter) { static const osd_dir_entry_type typelist[] = { ENTTYPE_DIR, ENTTYPE_FILE }; // extract a normalized subpath astring srcdir_subpath; normalized_subpath(srcdir_subpath, srcdir, srcrootlen + 1); // create an index file astring indexname; indexname.printf("%s%c%s", dstdir.cstr(), PATH_SEPARATOR[0], "index.html"); core_file *indexfile = create_file_and_output_header(indexname, tempheader, srcdir_subpath); // output the directory navigation core_fprintf(indexfile, "<h3>Viewing Directory: "); output_path_as_links(indexfile, srcdir_subpath, true, false); core_fprintf(indexfile, "</h3>"); // iterate first over directories, then over files int result = 0; for (int entindex = 0; entindex < ARRAY_LENGTH(typelist) && result == 0; entindex++) { osd_dir_entry_type entry_type = typelist[entindex]; // open the directory and iterate through it osd_directory *dir = osd_opendir(srcdir); if (dir == NULL) { result = 1; break; } // build up the list of files const osd_directory_entry *entry; int found = 0; list_entry *list = NULL; while ((entry = osd_readdir(dir)) != NULL) if (entry->type == entry_type && entry->name[0] != '.') { list_entry *lentry = new list_entry; lentry->name.cpy(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 list_entry **listarray = new list_entry *[found]; found = 0; for (list_entry *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]; } delete[] listarray; // iterate through each file for (list_entry *curlist = list; curlist != NULL && result == 0; curlist = curlist->next) { // add a header if (curlist == list) core_fprintf(indexfile, "\t<h2>%s</h2>\n\t<ul>\n", (entry_type == ENTTYPE_DIR) ? "Directories" : "Files"); // build the source filename astring srcfile; srcfile.printf("%s%c%s", srcdir.cstr(), PATH_SEPARATOR[0], curlist->name.cstr()); // if we have a file, output it astring dstfile; if (entry_type == ENTTYPE_FILE) { // make sure we care, first file_type type = FILE_TYPE_INVALID; for (int extnum = 0; extnum < ARRAY_LENGTH(extension_lookup); extnum++) if (core_filename_ends_with(curlist->name, extension_lookup[extnum].extension)) { type = extension_lookup[extnum].type; break; } // if we got a valid file, process it if (type != FILE_TYPE_INVALID) { dstfile.printf("%s%c%s.html", dstdir.cstr(), PATH_SEPARATOR[0], curlist->name.cstr()); if (indexfile != NULL) core_fprintf(indexfile, "\t<li><a href=\"%s.html\">%s</a></li>\n", curlist->name.cstr(), curlist->name.cstr()); result = output_file(type, srcrootlen, dstrootlen, srcfile, dstfile, srcdir == dstdir, tempheader, tempfooter); } } // if we have a directory, recurse else { dstfile.printf("%s%c%s", dstdir.cstr(), PATH_SEPARATOR[0], curlist->name.cstr()); if (indexfile != NULL) core_fprintf(indexfile, "\t<li><a href=\"%s/index.html\">%s/</a></li>\n", curlist->name.cstr(), curlist->name.cstr()); result = recurse_dir(srcrootlen, dstrootlen, srcfile, dstfile, tempheader, tempfooter); } } // close the list if we found some stuff if (list != NULL) core_fprintf(indexfile, "\t</ul>\n"); // free all the allocated entries while (list != NULL) { list_entry *next = list->next; delete list; list = next; } } if (indexfile != NULL) output_footer_and_close_file(indexfile, tempfooter, srcdir_subpath); return result; }
static void create_linked_file(const astring *dirname, const summary_file *curfile, const summary_file *prevfile, const summary_file *nextfile, const char *pngfile, const astring *tempheader, const astring *tempfooter) { astring *linkname = astring_alloc(); astring *filename = astring_alloc(); astring *title = astring_alloc(); core_file *linkfile; int listnum; /* create the filename */ astring_printf(filename, "%s.html", curfile->name); /* output header */ astring_printf(title, "%s Regressions (%s)", curfile->name, curfile->source); astring_printf(linkname, "%s" PATH_SEPARATOR "%s", astring_c(dirname), astring_c(filename)); linkfile = create_file_and_output_header(linkname, tempheader, title); if (linkfile == NULL) { fprintf(stderr, "Error creating file '%s'\n", astring_c(filename)); astring_free(title); astring_free(filename); astring_free(linkname); return; } /* link to the previous/next entries */ core_fprintf(linkfile, "\t<p>\n"); core_fprintf(linkfile, "\t<table width=\"100%%\">\n"); core_fprintf(linkfile, "\t\t<td align=\"left\" width=\"40%%\" style=\"border:none\">"); if (prevfile != NULL) core_fprintf(linkfile, "<a href=\"%s.html\"><< %s (%s)</a>", prevfile->name, prevfile->name, prevfile->source); core_fprintf(linkfile, "</td>\n"); core_fprintf(linkfile, "\t\t<td align=\"center\" width=\"20%%\" style=\"border:none\"><a href=\"index.html\">Home</a></td>\n"); core_fprintf(linkfile, "\t\t<td align=\"right\" width=\"40%%\" style=\"border:none\">"); if (nextfile != NULL) core_fprintf(linkfile, "<a href=\"%s.html\">%s (%s) >></a>", nextfile->name, nextfile->name, nextfile->source); core_fprintf(linkfile, "</td>\n"); core_fprintf(linkfile, "\t</table>\n"); core_fprintf(linkfile, "\t</p>\n"); /* output data for each one */ for (listnum = 0; listnum < list_count; listnum++) { int imageindex = -1; /* generate the HTML */ core_fprintf(linkfile, "\n\t<h2>%s</h2>\n", lists[listnum].version); core_fprintf(linkfile, "\t<p>\n"); core_fprintf(linkfile, "\t<b>Status:</b> %s\n", status_text[curfile->status[listnum]]); if (pngfile != NULL) imageindex = get_unique_index(curfile, listnum); if (imageindex != -1) core_fprintf(linkfile, " [%d]", imageindex); core_fprintf(linkfile, "\t</p>\n"); if (curfile->text[listnum] != NULL) { core_fprintf(linkfile, "\t<p>\n"); core_fprintf(linkfile, "\t<b>Errors:</b>\n"); core_fprintf(linkfile, "\t<pre>%s</pre>\n", curfile->text[listnum]); core_fprintf(linkfile, "\t</p>\n"); } } /* output link to the image */ if (pngfile != NULL) { core_fprintf(linkfile, "\n\t<h2>Screenshot Comparisons</h2>\n"); core_fprintf(linkfile, "\t<p>\n"); core_fprintf(linkfile, "\t<img src=\"%s\" />\n", pngfile); core_fprintf(linkfile, "\t</p>\n"); } /* output footer */ output_footer_and_close_file(linkfile, tempfooter, title); astring_free(title); astring_free(filename); astring_free(linkname); }
static int output_file(file_type type, int srcrootlen, int dstrootlen, const astring *srcfile, const astring *dstfile, int link_to_file) { 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; int linenum = 1; /* 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, link_to_file); 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; /* start with the line number */ dstptr += sprintf(dstptr, "<span style=\"" LINENUM_STYLE "\">%5d</span> ", linenum++); /* 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; }
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, FALSE); 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; list_entry *list = NULL; list_entry **listarray; 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 = 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 = 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]; } /* iterate through each file */ for (curlist = list; curlist != NULL && result == 0; curlist = curlist->next) { astring *srcfile, *dstfile; /* add a header */ if (curlist == list) 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], astring_c(curlist->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(astring_c(curlist->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], astring_c(curlist->name)); if (indexfile != NULL) core_fprintf(indexfile, "\t<li><a href=\"%s.html\">%s</a></li>\n", astring_c(curlist->name), astring_c(curlist->name)); result = output_file(type, srcrootlen, dstrootlen, srcfile, dstfile, astring_cmp(srcdir, dstdir) == 0); } } /* if we have a directory, recurse */ else { astring_printf(dstfile, "%s%c%s", astring_c(dstdir), PATH_SEPARATOR[0], astring_c(curlist->name)); if (indexfile != NULL) core_fprintf(indexfile, "\t<li><a href=\"%s/index.html\">%s/</a></li>\n", astring_c(curlist->name), astring_c(curlist->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 (list != NULL) core_fprintf(indexfile, "\t</ul>\n"); /* free all the allocated entries */ while (list != NULL) { list_entry *next = list->next; astring_free((astring *)list->name); free(list); list = next; } } error: if (indexfile != NULL) output_footer_and_close_file(indexfile); return result; }