Example #1
0
astring *image_info_astring(running_machine *machine, astring *string)
{
	device_image_interface *image = NULL;

	astring_printf(string, "%s\n\n", machine->gamedrv->description);

#if 0
	if (mess_ram_size > 0)
	{
		char buf2[RAM_STRING_BUFLEN];
		astring_catprintf(string, "RAM: %s\n\n", ram_string(buf2, mess_ram_size));
	}
#endif

	for (bool gotone = machine->m_devicelist.first(image); gotone; gotone = image->next(image))
	{
		const char *name = image->filename();
		if (name != NULL)
		{
			const char *base_filename;
			const char *info;
			char *base_filename_noextension;

			base_filename = image->basename();
			base_filename_noextension = strip_extension(base_filename);

			/* display device type and filename */
			astring_catprintf(string, "%s: %s\n", image->image_config().devconfig().name(), base_filename);

			/* display long filename, if present and doesn't correspond to name */
			info = image->longname();
			if (info && (!base_filename_noextension || mame_stricmp(info, base_filename_noextension)))
				astring_catprintf(string, "%s\n", info);

			/* display manufacturer, if available */
			info = image->manufacturer();
			if (info != NULL)
			{
				astring_catprintf(string, "%s", info);
				info = stripspace(image->year());
				if (info && *info)
					astring_catprintf(string, ", %s", info);
				astring_catprintf(string,"\n");
			}

			/* display playable information, if available */
			info = image->playable();
			if (info != NULL)
				astring_catprintf(string, "%s\n", info);

			if (base_filename_noextension != NULL)
				free(base_filename_noextension);
		}
		else
		{
			astring_catprintf(string, "%s: ---\n", image->image_config().devconfig().name());
		}
	}
	return string;
}
Example #2
0
static DEVICE_RESET( ti99_pcoden )
{
	logerror("ti99_pcode: reset\n");
	ti99_pcoden_state *pcode = get_safe_token(device);

	/* If the card is selected in the menu, register the card */
	if (input_port_read(device->machine(), "EXTCARD") & EXT_PCODE)
	{
		device_t *peb = device->owner();
		int success = mount_card(peb, device, &pcode_ncard, get_pebcard_config(device)->slot);
		if (!success) return;

		astring *region = new astring();
		astring_assemble_3(region, device->tag(), ":", pcode_region);

		pcode->rom0 = device->machine().region(astring_c(region))->base();
		pcode->rom1 = pcode->rom0 + 0x1000;
		pcode->rom2 = pcode->rom0 + 0x2000;
		pcode->grom = pcode->rom0 + 0x3000;
		pcode->bank_select = 0;
		pcode->selected = 0;

		astring *gromname = new astring();
		for (int i=0; i < 8; i++)
		{
			astring_printf(gromname, "grom_%d", i);
			pcode->gromdev[i] = device->subdevice(astring_c(gromname));
		}
	}
}
Example #3
0
static int generate_png_diff(const summary_file *curfile, const astring *destdir, const char *destname)
{
	bitmap_t *bitmaps[MAX_COMPARES] = { NULL };
	astring *srcimgname = astring_alloc();
	astring *dstfilename = astring_alloc();
	astring *tempname = astring_alloc();
	bitmap_t *finalbitmap = NULL;
	int width, height, maxwidth;
	int bitmapcount = 0;
	int listnum, bmnum;
	core_file *file = NULL;
	file_error filerr;
	png_error pngerr;
	int error = -1;
	int starty;

	/* generate the common source filename */
	astring_printf(dstfilename, "%s" PATH_SEPARATOR "%s", astring_c(destdir), destname);
	astring_printf(srcimgname, "snap" PATH_SEPARATOR "%s" PATH_SEPARATOR "final.png", curfile->name);

	/* open and load all unique bitmaps */
	for (listnum = 0; listnum < list_count; listnum++)
		if (curfile->matchbitmap[listnum] == listnum)
		{
			astring_printf(tempname, "%s" PATH_SEPARATOR "%s", lists[listnum].dir, astring_c(srcimgname));

			/* open the source image */
			filerr = core_fopen(astring_c(tempname), OPEN_FLAG_READ, &file);
			if (filerr != FILERR_NONE)
				goto error;

			/* load the source image */
			pngerr = png_read_bitmap(file, &bitmaps[bitmapcount++]);
			core_fclose(file);
			if (pngerr != PNGERR_NONE)
				goto error;
		}

	/* if there's only one unique bitmap, skip it */
	if (bitmapcount <= 1)
		goto error;

	/* determine the size of the final bitmap */
	height = width = 0;
	maxwidth = bitmaps[0]->width;
	for (bmnum = 1; bmnum < bitmapcount; bmnum++)
	{
		int curwidth;

		/* determine the maximal width */
		maxwidth = MAX(maxwidth, bitmaps[bmnum]->width);
		curwidth = bitmaps[0]->width + BITMAP_SPACE + maxwidth + BITMAP_SPACE + maxwidth;
		width = MAX(width, curwidth);

		/* add to the height */
		height += MAX(bitmaps[0]->height, bitmaps[bmnum]->height);
		if (bmnum != 1)
			height += BITMAP_SPACE;
	}

	/* allocate the final bitmap */
	finalbitmap = bitmap_alloc(width, height, BITMAP_FORMAT_ARGB32);
	if (finalbitmap == NULL)
		goto error;

	/* now copy and compare each set of bitmaps */
	starty = 0;
	for (bmnum = 1; bmnum < bitmapcount; bmnum++)
	{
		bitmap_t *bitmap1 = bitmaps[0];
		bitmap_t *bitmap2 = bitmaps[bmnum];
		int curheight = MAX(bitmap1->height, bitmap2->height);
		int x, y;

		/* iterate over rows in these bitmaps */
		for (y = 0; y < curheight; y++)
		{
			UINT32 *src1 = (y < bitmap1->height) ? BITMAP_ADDR32(bitmap1, y, 0) : NULL;
			UINT32 *src2 = (y < bitmap2->height) ? BITMAP_ADDR32(bitmap2, y, 0) : NULL;
			UINT32 *dst1 = BITMAP_ADDR32(finalbitmap, starty + y, 0);
			UINT32 *dst2 = BITMAP_ADDR32(finalbitmap, starty + y, bitmap1->width + BITMAP_SPACE);
			UINT32 *dstdiff = BITMAP_ADDR32(finalbitmap, starty + y, bitmap1->width + BITMAP_SPACE + maxwidth + BITMAP_SPACE);

			/* now iterate over columns */
			for (x = 0; x < maxwidth; x++)
			{
				int pix1 = -1, pix2 = -2;

				if (src1 != NULL && x < bitmap1->width)
					pix1 = dst1[x] = src1[x];
				if (src2 != NULL && x < bitmap2->width)
					pix2 = dst2[x] = src2[x];
				dstdiff[x] = (pix1 != pix2) ? 0xffffffff : 0xff000000;
			}
		}

		/* update the starting Y position */
		starty += BITMAP_SPACE + MAX(bitmap1->height, bitmap2->height);
	}

	/* write the final PNG */
	filerr = core_fopen(astring_c(dstfilename), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, &file);
	if (filerr != FILERR_NONE)
		goto error;
	pngerr = png_write_bitmap(file, NULL, finalbitmap, 0, NULL);
	core_fclose(file);
	if (pngerr != PNGERR_NONE)
		goto error;

	/* if we get here, we are error free */
	error = 0;

error:
	if (finalbitmap != NULL)
		bitmap_free(finalbitmap);
	for (bmnum = 0; bmnum < bitmapcount; bmnum++)
		if (bitmaps[bmnum] != NULL)
			bitmap_free(bitmaps[bmnum]);
	if (error)
		osd_rmfile(astring_c(dstfilename));
	astring_free(dstfilename);
	astring_free(srcimgname);
	astring_free(tempname);
	return error;
}
Example #4
0
static int compare_screenshots(summary_file *curfile)
{
	bitmap_t *bitmaps[MAX_COMPARES];
	int unique[MAX_COMPARES];
	int numunique = 0;
	int listnum;

	/* iterate over all files and load their bitmaps */
	for (listnum = 0; listnum < list_count; listnum++)
	{
		bitmaps[listnum] = NULL;
		if (curfile->status[listnum] == STATUS_SUCCESS)
		{
			astring *fullname = astring_alloc();
			file_error filerr;
			core_file *file;

			/* get the filename for the image */
			astring_printf(fullname, "%s" PATH_SEPARATOR "snap" PATH_SEPARATOR "%s" PATH_SEPARATOR "final.png", lists[listnum].dir, curfile->name);

			/* open the file */
			filerr = core_fopen(astring_c(fullname), OPEN_FLAG_READ, &file);

			/* if that failed, look in the old location */
			if (filerr != FILERR_NONE)
			{
				/* get the filename for the image */
				astring_printf(fullname, "%s" PATH_SEPARATOR "snap" PATH_SEPARATOR "_%s.png", lists[listnum].dir, curfile->name);

				/* open the file */
				filerr = core_fopen(astring_c(fullname), OPEN_FLAG_READ, &file);
			}

			/* if that worked, load the file */
			if (filerr == FILERR_NONE)
			{
				png_read_bitmap(file, &bitmaps[listnum]);
				core_fclose(file);
			}
			astring_free(fullname);
		}
	}

	/* now find all the different bitmap types */
	for (listnum = 0; listnum < list_count; listnum++)
	{
		curfile->matchbitmap[listnum] = 0xff;
		if (bitmaps[listnum] != NULL)
		{
			bitmap_t *this_bitmap = bitmaps[listnum];
			int compnum;

			/* compare against all unique bitmaps */
			for (compnum = 0; compnum < numunique; compnum++)
			{
				bitmap_t *base_bitmap = bitmaps[unique[compnum]];
				int bitmaps_differ;
				int x, y;

				/* if the sizes are different, we differ; otherwise start off assuming we are the same */
				bitmaps_differ = (this_bitmap->width != base_bitmap->width || this_bitmap->height != base_bitmap->height);

				/* compare scanline by scanline */
				for (y = 0; y < this_bitmap->height && !bitmaps_differ; y++)
				{
					UINT32 *base = BITMAP_ADDR32(base_bitmap, y, 0);
					UINT32 *curr = BITMAP_ADDR32(this_bitmap, y, 0);

					/* scan the scanline */
					for (x = 0; x < this_bitmap->width; x++)
						if (*base++ != *curr++)
							break;
					bitmaps_differ = (x != this_bitmap->width);
				}

				/* if we matched, remember which listnum index we matched, and stop */
				if (!bitmaps_differ)
				{
					curfile->matchbitmap[listnum] = unique[compnum];
					break;
				}

				/* if different from the first unique entry, adjust the status */
				if (bitmaps_differ && compnum == 0)
					curfile->status[listnum] = STATUS_SUCCESS_DIFFERENT;
			}

			/* if we're unique, add ourselves to the list */
			if (compnum >= numunique)
			{
				unique[numunique++] = listnum;
				curfile->matchbitmap[listnum] = listnum;
				continue;
			}
		}
	}

	/* free the bitmaps */
	for (listnum = 0; listnum < list_count; listnum++)
		if (bitmaps[listnum] != NULL)
			bitmap_free(bitmaps[listnum]);

	/* if all screenshots matched, we're good */
	if (numunique == 1)
		return BUCKET_GOOD;

	/* if the last screenshot matched the first unique one, we're good but changed */
	if (curfile->matchbitmap[listnum - 1] == unique[0])
		return BUCKET_GOOD_BUT_CHANGED_SCREENSHOTS;

	/* otherwise we're just changed */
	return BUCKET_CHANGED;
}
Example #5
0
static void output_report(const astring *dirname, const astring *tempheader, const astring *tempfooter, summary_file *filelist)
{
	summary_file *buckethead[BUCKET_COUNT], **buckettailptr[BUCKET_COUNT];
	summary_file *curfile;
	astring *title = astring_dupc("MAME Regressions");
	astring *tempname = astring_alloc();
	int listnum, bucknum;
	core_file *indexfile;
	int count = 0, total;

	/* initialize the lists */
	for (bucknum = 0; bucknum < BUCKET_COUNT; bucknum++)
	{
		buckethead[bucknum] = NULL;
		buckettailptr[bucknum] = &buckethead[bucknum];
	}

	/* compute the total number of files */
	total = 0;
	for (curfile = filelist; curfile != NULL; curfile = curfile->next)
		total++;

	/* first bucketize the games */
	for (curfile = filelist; curfile != NULL; 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] = NULL;

	/* output header */
	astring_printf(tempname, "%s" PATH_SEPARATOR "%s", astring_c(dirname), "index.html");
	indexfile = create_file_and_output_header(tempname, tempheader, title);
	if (indexfile == NULL)
	{
		fprintf(stderr, "Error creating file '%s'\n", astring_c(tempname));
		astring_free(tempname);
		astring_free(title);
		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] != NULL)
		{
			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(indexfile, tempfooter, title);
	astring_free(tempname);
	astring_free(title);
}
Example #6
0
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);
}
Example #7
0
astring *image_info_astring(running_machine &machine, astring *string)
{
	device_image_interface *image = NULL;

	astring_printf(string, "%s\n\n", machine.system().description);

#if 0
	if (mess_ram_size > 0)
	{
		char buf2[RAM_STRING_BUFLEN];
		astring_catprintf(string, "RAM: %s\n\n", ram_string(buf2, mess_ram_size));
	}
#endif

	for (bool gotone = machine.devicelist().first(image); gotone; gotone = image->next(image))
	{
		const char *name = image->filename();
		if (name != NULL)
		{
			const char *base_filename;
			const char *info;
			char *base_filename_noextension;

			base_filename = image->basename();
			base_filename_noextension = strip_extension(base_filename);

			/* display device type and filename */
			astring_catprintf(string, "%s: %s\n", image->device().name(), base_filename);

			/* display long filename, if present and doesn't correspond to name */
			info = image->longname();
			if (info && (!base_filename_noextension || mame_stricmp(info, base_filename_noextension)))
				astring_catprintf(string, "%s\n", info);

			/* display manufacturer, if available */
			info = image->manufacturer();
			if (info != NULL)
			{
				astring_catprintf(string, "%s", info);
				info = stripspace(image->year());
				if (info && *info)
					astring_catprintf(string, ", %s", info);
				astring_catprintf(string,"\n");
			}

			/* display supported information, if available */
			switch(image->supported()) {
				case SOFTWARE_SUPPORTED_NO : astring_catprintf(string, "Not supported\n"); break;
				case SOFTWARE_SUPPORTED_PARTIAL : astring_catprintf(string, "Partialy supported\n"); break;
				default : break;
			}

			if (base_filename_noextension != NULL)
				free(base_filename_noextension);
		}
		else
		{
			astring_catprintf(string, "%s: ---\n", image->device().name());
		}
	}
	return string;
}
Example #8
0
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 *map_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 (map_entry = depend_map->table[taghash]; map_entry != NULL; map_entry = map_entry->next)
							printf("\t%s \\\n", astring_c((astring *)map_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;
}
Example #9
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;
}