----------------------------------------
Begin resource changes:

1 of 2 / reportopt.rsrc: MENU/3200

append: "Game Properties" menu item after "Wrong Color"


2 of 2 / mamelang.rsrc: STR#128 "rStrings"

insert STR#128 / 20:
    add string "MAME Game Properties",
    after: "MAME Wrong Color List",
    before: "ROM Audit"

End resource changes.
----------------------------------------

--- macstrings-orig.h	Fri Jul  9 15:12:57 2004
+++ macstrings.h	Fri Jul  9 15:13:14 2004
@@ -68,4 +68,5 @@
 	kImpColorList,
 	kWrongColorList,
+    kGamePropertiesList,
 	kROMAudit,
 	kSampleAudit,
--- macreports-orig.h	Fri Jul  9 15:14:05 2004
+++ macreports.h	Fri Jul  9 15:52:46 2004
@@ -30,8 +30,19 @@
 	kReportNoSound,
 	kReportImpColor,
-	kReportWrongColor
+	kReportWrongColor,
+	kReportGameProperties
 }
 eReportType;
 
+/*##########################################################################
+	TABULAR-REPORT CONSTANTS
+##########################################################################*/
+#define kclonenotworking 1
+#define kworking 2
+#define knotworking 3
+#define parentnotworkingcloneok 4
+#define kisparent 1
+#define kisclone 2
+#define kissingleton 3
 
 /*##########################################################################
--- macreports-orig.c	Fri Jul  9 15:20:30 2004
+++ macreports.c	Wed Jul 14 15:57:49 2004
@@ -83,5 +83,6 @@
 	kNoSoundList,
 	kImpColorList,
-	kWrongColorList
+	kWrongColorList,
+	kGamePropertiesList //kReportGameProperties "Game Properties (Tab-delimited)"
 };
 
@@ -159,4 +160,52 @@
 extern int					gTotalBIOS;
 
+extern void GetPixelAspect(struct InternalMachineDriver inDriver,
+						   const struct GameDriver *inGamedrv,
+						   int * outpixelx, int * outpixely);
+extern Boolean	WhichBIOS(const struct GameDriver *inDrv, const char **outBIOSname, const char **outBIOSdesc);
+#ifndef MAX_PLAYERS
+#	define MAX_PLAYERS	16 // proper way to do this? 16 is a guess based on 0.77
+#endif	/* MAX_PLAYERS */
+
+#ifndef MAX_ANALOG
+#	define MAX_ANALOG	32 // proper way to do this? 32 is a guess
+#endif	/* MAX_ANALOG */
+
+#ifndef MAX_DIPSW
+#	define MAX_DIPSW	65 // proper way to do this? 64 is a guess
+#endif	/* MAX_DIPSW */
+
+typedef struct
+{
+	Boolean		analog_found;
+	Boolean		digital_found;
+	Boolean		other_found;
+	Boolean		service_found;
+	
+	int			nplayers;
+	/* analog inputs */
+	const char*	acontrol_desc[MAX_PLAYERS][MAX_ANALOG];
+	int			nanalog[MAX_PLAYERS];
+	
+	/* digital inputs */
+	int			nbutton[MAX_PLAYERS];
+	const char*	dcontrol_desc[MAX_PLAYERS];
+	int			ndigital;
+	int			nstart;
+	
+	/* other inputs */
+	Boolean		tilt_sensor_found;
+	int			nunknown;
+	int			ncoin;
+	
+	/* service inputs */
+	Boolean		analog_adjuster_found;
+	int			ncoin_service;
+	Boolean		service_switch_found;
+	int			ndip;
+	const char*	dipname[MAX_DIPSW];
+}
+controls_found;
+extern void			ControlsGetter(const struct GameDriver *inGame, controls_found *outControls);
 
 /*##########################################################################
@@ -175,4 +224,16 @@
 static void identify_zip(const char* zipname);
 
+static void PrintTabReportHeader(void);
+
+int HasSamples(struct InternalMachineDriver driver);
+
+void SuperNotWorking(const struct GameDriver *inDrv, Boolean isClone,
+					 int * outNotworking, int * outParentorclone);
+
+void PrintGameProperties(struct InternalMachineDriver /*in*/driver,
+						   const struct GameDriver *gamedrv/*in*/,
+						   Boolean isClone/*in*/);
+
+static void			ControlsFormatterReport(controls_found inControls);
 
 /*##########################################################################
@@ -410,5 +471,9 @@
 				"The following games have totally wrong color:"));
 			break;
+		case kReportGameProperties:
+			(void)PrintTabReportHeader();
+			break;
 	}
+	if (!(inOpt->type == kReportGameProperties))
 	rPrintf ("\n\n");
 	
@@ -443,14 +508,5 @@
 		if (inOpt->type == kReportGameSamples)
 		{
-			// Loop over the sound systems and see if one of them is SOUND_SAMPLES
-			for (i = 0; i < MAX_SOUND; i++)
-			{
-				const struct MachineSound *sound = &driver.sound[i];
-			
-				// This assumes that only one sound subsystem uses samples
-				if (sound->sound_type == SOUND_SAMPLES)
-					hasSamples = i;
-			}
-		
+			hasSamples = HasSamples(driver);
 			if (hasSamples == -1) continue;
 		}
@@ -461,5 +517,13 @@
 			
 		// name of the game
+		if (!(inOpt->type == kReportGameProperties))
+		{
 		rPrintf ("%-10s\"%s\"\n", gamedrv->name, gamedrv->description);
+			//rPrintf ("%s\t%s\n", gamedrv->name, gamedrv->description); // same but tab delimited
+		}
+		else if (inOpt->type == kReportGameProperties)
+		{
+			(void)PrintGameProperties(driver, gamedrv, isClone);
+		}
 		
 		// display ROMs needed
@@ -641,4 +705,5 @@
 	} // end for loop
 	
+	if (!(inOpt->type == kReportGameProperties))
 	rPrintf ("\n");
 	
@@ -687,4 +752,7 @@
 			rPrintf (": %4d\n", count);
 			break;
+		case kReportGameProperties:
+			// no trailing summary for tab-delimited report
+			break;
 	}
 
@@ -693,6 +761,577 @@
 }
 
+
+#pragma mark -
+#pragma mark ¥ Tab-delimited Report Routines
+
+//===============================================================================
+//	PrintTabReportHeader
+//
+//	Simply outputs column headers to the report.
+//===============================================================================
+
+static void PrintTabReportHeader(void)
+{
+	rPrintf ("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s Hz\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
+			 "Name",
+			 "Descriptive name",
+			 "Manufacturer",
+			 "Year",
+			 "Video type",
+			 "Stereo",
+			 "Video orientation",
+			 "Width",
+			 "Height",
+			 "Colors",
+			 "Video refresh",
+			 "Parent",
+			 "BIOS",
+			 /*"bios region",*/
+			 "Source file",
+			 "Sound status",
+			 "Color status",
+			 "Samples",
+			 "Multiple monitor",
+			 "Pixel aspect",
+			 "Not working",
+			 "Parent or clone",
+			 "CPUs",
+			 "Sound CPUs",
+			 "Analog controls",
+			 "Digital controls",
+			 "Other inputs",
+			 "Service inputs",
+			 "Dip-switches"
+			 );
+	// TODO: "CHD filename", "Hiscore capable", "Artwork type"
+}
+
+
+//===============================================================================
+//	PrintGameProperties
+//
+//	Generates all the game properties for the tab-delimited report (kReportGameProperties).
+//===============================================================================
+void PrintGameProperties(struct InternalMachineDriver /*in*/driver,
+						 const struct GameDriver *gamedrv/*in*/,
+						 Boolean isClone)
+{
+#include <libgen.h> // basename(3) for gamedrv->source_file
+
+	int hasSamples = -1;
+	hasSamples = HasSamples(driver);
+	
+	// calculate pixel aspect-ratio
+	int pixelx, pixely;
+	GetPixelAspect(driver, gamedrv, &pixelx, &pixely);
+
+	const char *BIOSname = "";
+	{
+		if (! WhichBIOS(gamedrv, &BIOSname, NULL/*&BIOSdesc*/))
+			BIOSname = "none";
+	}
+	
+	
+	// calculate "not working" status:
+	char *notworking = "";
+	char *parentorclone = "";
+	{
+		int outNotworking = 0;
+		int outParentorclone = 0;
+		SuperNotWorking(gamedrv, isClone, &outNotworking, &outParentorclone);
+		// Localization not important here: any DB frontend which imports the
+		// tab-delimited data can handle the l8n.
+		switch (outNotworking)
+		{		
+			case kclonenotworking:
+				notworking = "Clone not working";
+				break;
+			case kworking:
+				notworking = "Working";
+				break;
+			case knotworking:
+				notworking = "Not working";
+				break;
+			case parentnotworkingcloneok:
+				notworking = "Parent not working, Clone playable";
+				break;
+			default:
+				notworking = "DEBUG:notworkingERROR!";
+				break;
+		}
+		switch (outParentorclone)
+		{		
+			case kisparent:
+				parentorclone = "parent";
+				break;
+			case kisclone:
+				parentorclone = "clone";
+				break;
+			case kissingleton:
+				parentorclone = "singleton";
+				break;
+			default:
+				parentorclone = "DEBUG:parentorcloneERROR!";
+				break;
+		}
+	} //end not working
+	
+	rPrintf ("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%d\t%d\t%d\t%f Hz\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%d:%d\t%s\t%s",
+			 gamedrv->name,
+			 gamedrv->description,
+			 gamedrv->manufacturer,
+			 gamedrv->year,
+			 (driver.video_attributes & VIDEO_TYPE_VECTOR) ? "Vector" : "Raster",
+			 (driver.sound_attributes & SOUND_SUPPORTS_STEREO) ? "Stereo" : "Mono",
+			 (gamedrv->flags & ORIENTATION_SWAP_XY) ? "Vertical" : "Horizontal",
+			 (driver.default_visible_area.max_x - driver.default_visible_area.min_x + 1),
+			 (driver.default_visible_area.max_y - driver.default_visible_area.min_y + 1),
+			 driver.total_colors,
+			 driver.frames_per_second,
+			 
+			 // Get parent name. Note: if game has a bios, internally it appears as if the game is a clone!
+			 (isClone) ? (IsBIOS(gamedrv->clone_of->name) ? ""
+						  								  : gamedrv->clone_of->name)
+					   : "", // not a clone, has no parent
+			 
+			 /*(gamedrv->bios) ? gamedrv->bios->_name : "",*/ // bios' region (not interested in this info yet)
+			 BIOSname, // WhichBIOS()
+			 basename(gamedrv->source_file),
+
+			 // hopefully GAME_NO_SOUND and GAME_IMPERFECT_SOUND are mutually exclusive
+			 (gamedrv->flags & GAME_NO_SOUND) ? "no sound"
+			 								  : ((gamedrv->flags & GAME_IMPERFECT_SOUND) ? "imperfect sound"
+																						 : "good sound"),
+
+			 // hopefully GAME_WRONG_COLORS and GAME_IMPERFECT_COLORS are mutually exclusive
+			 (gamedrv->flags & GAME_WRONG_COLORS) ? "totally wrong color"
+			 									  : ((gamedrv->flags & GAME_IMPERFECT_COLORS) ? "imperfect color"
+																							  : "good color"),
+
+			 // Driver marked as having samples but none were found, assume they are emulated (integrated)
+			 hasSamples > -1 ? (DriverHasSamples(gamedrv) ? "Samples"
+														  : "Samples (Integrated)")
+							 : "Samples not required",
+
+			 (driver.video_attributes & VIDEO_DUAL_MONITOR) ? "Multiple monitor"
+															: "Single monitor",
+			 pixelx, pixely, // GetPixelAspect()
+			 notworking, // SuperNotWorking()
+			 parentorclone // SuperNotWorking()
+			 );
+	
+
+	// CPUs
+	// Copied from InfoTextHardwareInfo macinfo.c
+	rPrintf ("\t");
+	{
+		Boolean cpu_found = false;
+		int i;
+
+		for (i = 0; i < MAX_CPU && driver.cpu[i].cpu_type; i++)
+		{
+			if (driver.cpu[i].cpu_clock >= 1000000)
+			{
+				if (cpu_found) rPrintf(", ");
+				rPrintf("%s %d.%06d MHz",
+						cputype_name(driver.cpu[i].cpu_type),
+						driver.cpu[i].cpu_clock / 1000000,
+						driver.cpu[i].cpu_clock % 1000000);
+				cpu_found = true;
+			}
+			else
+			{
+				if (cpu_found) rPrintf(", ");
+				rPrintf("%s %d.%03d kHz",
+						cputype_name(driver.cpu[i].cpu_type),
+						driver.cpu[i].cpu_clock / 1000,
+						driver.cpu[i].cpu_clock % 1000);
+				cpu_found = true;
+			}
+			
+			if (driver.cpu[i].cpu_type & CPU_AUDIO_CPU)
+				rPrintf (" (sound)");
+		}
+		if (!cpu_found)
+			rPrintf ("no CPUs"); // maybe for new incomplete drivers?
+	}
+	
+	// Sound CPUs
+	// Copied from InfoTextHardwareInfo macinfo.c
+	rPrintf ("\t");
+	{
+		Boolean cpu_found = false;
+		int i;
+
+		for (i = 0; i < MAX_SOUND && driver.sound[i].sound_type; i++)
+		{
+
+			if (cpu_found) rPrintf(", ");
+			if (sound_num(&driver.sound[i]))
+			{
+				rPrintf("%d x ",sound_num(&driver.sound[i]));
+				cpu_found = true;
+			}
+			
+			rPrintf("%s", sound_name(&driver.sound[i]));
+			
+			if (sound_clock(&driver.sound[i]))
+			{
+				if (sound_clock(&driver.sound[i]) >= 1000000)
+				{
+					rPrintf(" %d.%06d MHz",
+							sound_clock(&driver.sound[i]) / 1000000,
+							sound_clock(&driver.sound[i]) % 1000000);
+					cpu_found = true;
+				}
+				else
+				{
+					rPrintf(" %d.%03d MHz",
+							sound_clock(&driver.sound[i]) / 1000,
+							sound_clock(&driver.sound[i]) % 1000);
+					cpu_found = true;
+				}
+			}
+			
+			//txtprint("\n");
+		}
+		if (!cpu_found)
+			rPrintf ("no sound CPUs");
+	}
+	
+	rPrintf ("\t");
+	{
+		controls_found controlList;
+		// Check for analog & digital controls
+		ControlsGetter(gamedrv, /*out*/&controlList);
+		
+		// Format controls output text with tabs for Report
+		ControlsFormatterReport(/*in*/controlList);
+	}
+	rPrintf("\n"); //next rom
+}
+
+
+//===============================================================================
+//  ControlsFormatterReport(struct controls_found inControls)
+//
+// Takes the data from the controls_found struct which was populated by
+// the ControlsGetter() function and formats the output for a report.
+//
+//  The sister function to this is ControlsFormatterInfoPane() in macinfo.c,
+//  which does not print out dipswitch names.
+//===============================================================================
+static void ControlsFormatterReport(controls_found c)
+{
+#define ALSO_PRINT_DIPSWITCH_NAMES 1
+
+	// Analog Controls column
+	if (c.analog_found)
+	{
+		//rPrintf ("\nThis game has analog controls:");
+		int p = 1;
+		int a = 0;
+		for (p = 1; p <= c.nplayers+1; ++p)
+		{
+			Boolean analog_found = false;
+			for (a = 0; a < c.nanalog[p]; ++a)
+			{
+				if (analog_found) rPrintf("; "); //next player
+				if (!analog_found)
+					rPrintf("P%d: ", p);
+				// analog control name
+				if (c.acontrol_desc[p][a])
+				{
+					if (analog_found) rPrintf(", ");
+					rPrintf("%s", c.acontrol_desc[p][a]);
+					analog_found = true;
+				}
+			}
+			//if (analog_found) rPrintf("; "); //next player
+		}
+	}
+	else
+		rPrintf ("no analog controls");
+	
+	rPrintf("\t");
+
+	// Digital Controls column
+	if (c.digital_found)
+	{
+		//rPrintf ("\nThis game has digital controls:");
+		int p = 1;
+		for (p = 1; p <= c.nplayers+1; ++p)
+		{
+			Boolean digital_found = false;
+			if (c.nbutton[p] || c.dcontrol_desc[p])
+				rPrintf("P%d: ", p);
+			
+			switch (c.nbutton[p])
+			{
+				case 0:
+					//rPrintf("(no buttons)");
+					break;
+				case 1:
+					digital_found = true;
+					rPrintf("one button");
+					break;
+					//case 2: // future localization
+				default:
+					digital_found = true;
+					rPrintf("(%d) buttons", c.nbutton[p]);
+					break;
+			}
+			// digital joysticks
+			if (c.dcontrol_desc[p])
+			{
+				if (digital_found) rPrintf(", ");
+				digital_found = true;
+				rPrintf("%s", c.dcontrol_desc[p]);
+			}
+			//else
+			//	rPrintf("(no joystick)");
+			if (digital_found) rPrintf("; "); //next player
+		}
+		
+		switch (c.nstart)
+		{
+			case 0:
+				//rPrintf("Start buttons: (none)");
+				break;
+			case 1:
+				rPrintf("Start button: (one)");
+				break;
+				//case 2: // future localization
+			default:
+				rPrintf("Start buttons: (%d)", c.nstart);
+				break;
+		}
+	}
+	else
+		rPrintf ("no digital controls");
+	
+	rPrintf("\t");
+	
+	// Other inputs column
+	if (c.other_found)
+	{
+		Boolean other_found = false;
+		//rPrintf("\nOther inputs:");
+		if (c.tilt_sensor_found)
+		{
+			rPrintf("Tilt sensor");
+			other_found = true;
+		}
+		switch (c.nunknown)
+		{
+			case 0:
+				break;
+			case 1:
+				if (other_found) rPrintf(", ");
+				rPrintf("Unknown control: (one)");
+				other_found = true;
+				break;
+				//case 2: // future localization
+			default:
+				if (other_found) rPrintf(", ");
+				rPrintf("Unknown controls: (%d)", c.nunknown);
+				other_found = true;
+				break;
+		}
+		switch (c.ncoin)
+		{
+			case 0:
+				//rPrintf("Coin slots: (none)");
+				break;
+			case 1:
+				if (other_found) rPrintf(", ");
+				rPrintf("Coin slot: (one)");
+				other_found = true;
+				break;
+				//case 2: // future localization
+				// http://www.gnu.org/software/gettext/manual/html_node/gettext_150.html
+			default:
+				if (other_found) rPrintf(", ");
+				rPrintf("Coin slots: (%d)", c.ncoin);
+				other_found = true;
+				break;
+		}
+	}
+	else
+		rPrintf ("no other inputs");
+	
+	rPrintf("\t");
+	
+	// Service inputs column
+	if (c.service_found)
+	{
+		Boolean service_found = false;
+		//rPrintf("\nService inputs:");
+		if (c.analog_adjuster_found)
+		{
+			rPrintf("Analog adjuster");
+			service_found = true;
+		}
+		if (c.service_switch_found)
+		{
+			if (service_found) rPrintf(", ");
+			rPrintf("Service switch");
+			service_found = true;
+		}
+		switch (c.ncoin_service)
+		{
+			case 0:
+				//rPrintf("Service coin: (none)");
+				break;
+			case 1:
+				if (service_found) rPrintf(", ");
+				rPrintf("Service coin: (one)");
+				service_found = true;
+				break;
+				//case 2: // future localization
+			default:
+				if (service_found) rPrintf(", ");
+				rPrintf("Service coin: (%d)", c.ncoin_service);
+				service_found = true;
+				break;
+		}
+		switch (c.ndip)
+		{
+			case 0:
+				//rPrintf("Dip-switches: (none)");
+				break;
+			case 1:
+				if (service_found) rPrintf(", ");
+				rPrintf("Dip-switch: (one)");
+				service_found = true;
+				break;
+				//case 2: // future localization
+			default:
+				if (service_found) rPrintf(", ");
+				rPrintf("Dip-switches: (%d)", c.ndip);
+				service_found = true;
+				break;
+		}
+	}
+	else
+		rPrintf ("no service inputs");
+
+	
+	// Dip-switch names column
+
+#ifdef ALSO_PRINT_DIPSWITCH_NAMES
+	rPrintf("\t");
+
+	if (c.ndip)
+	{
+		int p = 1;
+		Boolean dipfound = false;
+		
+		for (p = 1; p <= c.ndip; ++p)
+		{
+			if (c.dipname[p])
+			{
+				if (dipfound) rPrintf(", ");
+				rPrintf("%s", c.dipname[p]);
+				dipfound = true;
+			}
+		}
+	}
+	else
+		rPrintf ("no dip-switches");
+#endif /* ALSO_PRINT_DIPSWITCH_NAMES */
+}
+
+
+//===============================================================================
+//  SuperNotWorking
+//
+//  Calculate "not working" status, and is a parent, clone or singleton?
+//
+//  For parents:
+//  "working"				(parent working and if clones, all clones working)
+//  "clone not working"		(parent working, at least one clone not working)
+//  "not working"			(parent not working and if clones, all clones not working)
+//  "not working, clone ok"	(parent not working, at least one clone working)
+//
+//  For clones, just "working" or "not working"
+//
+//  Also, is it a parent, clone, or singleton (i.e. a cloneless parent)?
+//===============================================================================
+void SuperNotWorking(const struct GameDriver *inDrv, Boolean isClone,
+					 int * outNotworking, int * outParentorclone)
+{
+	int i = 0;
+	int clonecount = 0;
+	int clonenotworkingcount = 0;
+	if (!isClone) {
+		// loop over game drivers to count non-working clones of this parent
+		for (i = 0; drivers[i]; i++)
+		{
+			if (drivers[i]->clone_of == inDrv)
+			{
+				clonecount++;
+				if (IsBroken(drivers[i])) {
+					clonenotworkingcount++;
+				}
+			}
+		}
+		//printf("DEBUG: name=%s, isClone=%d, clonecount=%d, clonenotworkingcount=%d\n",
+		//	   inDrv->name, isClone, clonecount, clonenotworkingcount);
+	}
+	
+	if (!IsBroken(inDrv))
+	{
+		if (clonenotworkingcount > 0)
+			*outNotworking = kclonenotworking;
+		else
+			*outNotworking = kworking;
+	}
+	else
+	{ // parent not working
+		if (clonecount == clonenotworkingcount)
+			*outNotworking = knotworking;
+		else
+			*outNotworking = parentnotworkingcloneok;
+	}
+
+	// clone, parent, or singleton (cloneless)?
+	if (isClone)
+	{
+		*outParentorclone = kisparent;
+	}
+	else
+	{
+		if (clonecount > 0)
+			*outParentorclone = kisclone;
+		else
+			*outParentorclone = kissingleton;
+	}
+}
+
+
 #pragma mark -
 #pragma mark ¥ Audit Routines
+
+
+//===============================================================================
+//	HasSamples
+//
+//  Loop over the sound systems and see if one of them is SOUND_SAMPLES
+//===============================================================================
+int HasSamples(struct InternalMachineDriver driver)
+{
+	int hasSamples = -1;
+	int i = 0;
+	for (i = 0; i < MAX_SOUND; i++)
+	{
+		const struct MachineSound *sound = &driver.sound[i];
+		
+		// This assumes that only one sound subsystem uses samples
+		if (sound->sound_type == SOUND_SAMPLES)
+			hasSamples = i;
+	}
+	return hasSamples;
+}
 
 
--- macinfo-orig.c	Wed Jul 14 16:11:30 2004
+++ macinfo.c	Wed Jul 14 16:49:08 2004
@@ -98,4 +98,48 @@
 
 
+#ifndef MAX_PLAYERS
+#	define MAX_PLAYERS	16 // proper way to do this? 16 is a guess based on 0.77
+#endif	/* MAX_PLAYERS */
+
+#ifndef MAX_ANALOG
+#	define MAX_ANALOG	32 // proper way to do this? 32 is a guess
+#endif	/* MAX_ANALOG */
+
+#ifndef MAX_DIPSW
+#	define MAX_DIPSW	65 // proper way to do this? 64 is a guess
+#endif	/* MAX_DIPSW */
+
+typedef struct
+{
+	Boolean		analog_found;
+	Boolean		digital_found;
+	Boolean		other_found;
+	Boolean		service_found;
+	
+	int			nplayers;
+	/* analog inputs */
+	const char*	acontrol_desc[MAX_PLAYERS][MAX_ANALOG];
+	int			nanalog[MAX_PLAYERS];
+	
+	/* digital inputs */
+	int			nbutton[MAX_PLAYERS];
+	const char*	dcontrol_desc[MAX_PLAYERS];
+	int			ndigital;
+	int			nstart;
+	
+	/* other inputs */
+	Boolean		tilt_sensor_found;
+	int			nunknown;
+	int			ncoin;
+	
+	/* service inputs */
+	Boolean		analog_adjuster_found;
+	int			ncoin_service;
+	Boolean		service_switch_found;
+	int			ndip;
+	const char*	dipname[MAX_DIPSW];
+}
+controls_found;
+
 /*##########################################################################
 	GLOBALS
@@ -144,4 +188,10 @@
 
 static void 		InfoTextHardwareInfo(const struct GameDriver *inGame);
+void				GetPixelAspect(struct InternalMachineDriver inDriver,
+								   const struct GameDriver *inGamedrv,
+								   int * outpixelx, int * outpixely);
+Boolean				WhichBIOS(const struct GameDriver *inDrv, const char **outBIOSname, const char **outBIOSdesc);
+void			ControlsGetter(const struct GameDriver *inGame, controls_found *outControls);
+static void			ControlsFormatterInfoPane(controls_found inControls);
 static void 		InfoTextHistory(const struct GameDriver *inGame);
 static void 		InfoTextMiniAudit(const struct GameDriver *inGame);
@@ -1957,5 +2007,4 @@
 	expand_machine_driver(inGame->drv, &driver);
 
-	
 	txtClear();
 	txtJust(teCenter);
@@ -2019,19 +2068,65 @@
 	else
 	{
-		int pixelx,pixely,tmax,tmin,rem;
+		int pixelx, pixely;
+		GetPixelAspect(driver, inGame, &pixelx, &pixely);
 
-		pixelx = 4 * (driver.default_visible_area.max_y - driver.default_visible_area.min_y + 1);
-		pixely = 3 * (driver.default_visible_area.max_x - driver.default_visible_area.min_x + 1);
+		txtprint("\nScreen resolution:\n");
+		txtprint("%d x %d (%s) %f Hz\npixel aspect ratio %d:%d\n",
+				 driver.default_visible_area.max_x - driver.default_visible_area.min_x + 1,
+				 driver.default_visible_area.max_y - driver.default_visible_area.min_y + 1,
+				 (inGame->flags & ORIENTATION_SWAP_XY) ? "V" : "H",
+				 driver.frames_per_second,
+				 pixelx,pixely);
+#if 0
+		txtprint("%d colors ",driver.total_colors);
+		if (driver.video_attributes & VIDEO_MODIFIES_PALETTE)
+			txtprint("(dynamic)\n");
+		else 
+			txtprint("(static)\n");
+#endif
+	}
+	{
+		const char *BIOSname = "";
+		const char *BIOSdesc = "";
+		
+		if (WhichBIOS(inGame, &BIOSname, &BIOSdesc))
+		{
+			txtprint("\nBIOS:\n");
+			txtprint("%s (%s)\n", BIOSdesc, BIOSname);
+		}
+	}
+
+	controls_found controlList;
+	// Check for analog & digital controls
+	ControlsGetter(inGame, /*out*/&controlList);
+
+	// Format output text for Hardware Info pane
+	ControlsFormatterInfoPane(/*in*/controlList);
+}
+
+//===============================================================================
+//  GetPixelAspect
+//
+// Calculate game's pixel aspect ratio and output into outpixelx, outpixely
+//===============================================================================
+void GetPixelAspect(struct InternalMachineDriver inDriver,
+					const struct GameDriver *inGamedrv,
+					int * outpixelx, int * outpixely)
+{
+	int tmax, tmin, rem;
+	
+	*outpixelx = 4 * (inDriver.default_visible_area.max_y - inDriver.default_visible_area.min_y + 1);
+	*outpixely = 3 * (inDriver.default_visible_area.max_x - inDriver.default_visible_area.min_x + 1);
 
 		/* calculate MCD */
-		if (pixelx >= pixely)
+	if (*outpixelx >= *outpixely)
 		{
-			tmax = pixelx;
-			tmin = pixely;
+		tmax = *outpixelx;
+		tmin = *outpixely;
 		}
 		else
 		{
-			tmax = pixely;
-			tmin = pixelx;
+		tmax = *outpixely;
+		tmin = *outpixelx;
 		}
 		while ((rem = tmax % tmin) != 0)
@@ -2042,79 +2137,558 @@
 		/* tmin is now the MCD */
 
-		pixelx /= tmin;
-		pixely /= tmin;
+	*outpixelx /= tmin;
+	*outpixely /= tmin;
 
 		/* If it's a horizontal game but the vertical size is at least twice as large */
 		/* assume it's a dual-monitor setup like Punchout */
-		if (!(inGame->flags & ORIENTATION_SWAP_XY) && (pixelx / 2 > pixely))
-			pixelx /= 2;
+	if (!(inGamedrv->flags & ORIENTATION_SWAP_XY) && (*outpixelx / 2 > *outpixely))
+		*outpixelx /= 2;
 
-		txtprint("\nScreen resolution:\n");
-		txtprint("%d x %d (%s) %f Hz\npixel aspect ratio %d:%d\n",
-				driver.default_visible_area.max_x - driver.default_visible_area.min_x + 1,
-				driver.default_visible_area.max_y - driver.default_visible_area.min_y + 1,
-				(inGame->flags & ORIENTATION_SWAP_XY) ? "V" : "H",
-				driver.frames_per_second,
-				pixelx,pixely);
-#if 0
-		txtprint("%d colors ",driver.total_colors);
-		if (driver.video_attributes & VIDEO_MODIFIES_PALETTE)
-			txtprint("(dynamic)\n");
+}
+
+//===============================================================================
+//  WhichBIOS
+//
+//  Given a GameDriver, returns true or false if game has a BIOS. When true, also
+//  ouputs the name & descriptive name of the BIOS if pointers are supplied.
+//===============================================================================
+Boolean WhichBIOS(const struct GameDriver *inGame,
+				  const char **outBIOSname, const char **outBIOSdesc)
+{
+	// if(inGame->bios) // this only seems to work for neogeo??
+	Boolean is_nota_clone = false;
+	
+	is_nota_clone = !IsClone(inGame);
+	
+	if ((!is_nota_clone && (inGame->clone_of->clone_of->name != "")
+		 && IsBIOS(inGame->clone_of->clone_of->name))
+		|| (is_nota_clone && (inGame->clone_of->name != "")
+			&& IsBIOS(inGame->clone_of->name))
+		)
+	{
+		if (is_nota_clone)
+		{
+			if (! outBIOSdesc == NULL) // proper way to check for a null pointer?
+				*outBIOSdesc = inGame->clone_of->description;
+			if (! outBIOSname == NULL)
+				*outBIOSname = inGame->clone_of->name;
+			return true;
+		}
 		else 
-			txtprint("(static)\n");
-#endif
+		{
+			if (! outBIOSdesc == NULL)
+				*outBIOSdesc = inGame->clone_of->clone_of->description;
+			if (! outBIOSname == NULL)
+				*outBIOSname = inGame->clone_of->clone_of->name;
+			return true;
+		}
 	}
+	return false;
+}
 
-	/* Check for analog controls */
 	
-	{
-		const struct InputPort* in;
+//===============================================================================
+//  ControlsGetter(inGame, controls_found outControls)
+//
+//  Check which inputs a game has: analog, digital, service switches, coins, etc.
+//  Populates the controls_found struct which will later be formatted for
+//  output to the Hardware Info pane by the ControlsFormatterInfoPane() function.
+//  Alternately it could be formatted for the tab-delimited report by another
+//  function, ControlsFormatterReport() in macreports.c.
+//
+//  Reference:
+//  src/inptport.h: enum {}
+//  src/info.c: print_game_input()
+//===============================================================================
+void ControlsGetter(const struct GameDriver *inGame, controls_found *c)
+{
+	const struct InputPort* input;
 		begin_resource_tracking();
-		in = input_port_allocate(inGame->construct_ipt);
+	input = input_port_allocate(inGame->construct_ipt);
 
-		int num;
-		int analog_found = 0;
+	/* Note that each player could have different controls, although this
+	 * would be rare. e.g. the two-seater version of 'firetrk' "Fire Truck",
+	 * the four-player 'teamqb' "John Elway's Team Quarterback"
+	 */
+	int i;
+	int j;
+	// init arrays
+	for (i=0; i<=MAX_PLAYERS; i++) {
+		c->nbutton[i] = 0;
+		c->dcontrol_desc[i] = 0/*""*/;
+		c->nanalog[i] = 0;
+	}
+	for (i=0; i<=MAX_PLAYERS; i++) {
+		for (j=0; j<=MAX_ANALOG; j++) {
+			c->acontrol_desc[i][j] = 0/*""*/;
+		}
+	}
+	for (i=0; i<=MAX_DIPSW; i++) {
+		c->dipname[i] = 0/*""*/;
+	}
+	// init rest
+	c->analog_found = false;
+	c->digital_found = false;
+	c->other_found = false;
+	c->service_found = false;
+	
+	c->nplayers = 0;
+	
+	/* digital inputs */
+	c->ndigital = 0;
+	c->nstart = 0;
+	
+	/* other inputs */
+	c->tilt_sensor_found = false;
+	c->nunknown = 0;
+	c->ncoin = 0;
+	
+	/* service inputs */
+	c->analog_adjuster_found = false;
+	c->ncoin_service = 0;
+	c->service_switch_found = false;
+	c->ndip = 0;
+	
+	
+	while (input->type != IPT_END)
+	{
+		int playernum = 0;
+		
+		if (playernum < input->player)
+			playernum = input->player;
+		
+		if (playernum > c->nplayers)
+			c->nplayers = playernum;
+		if ((input->type < IPT_EXTENSION) || (input->type > IPT_UI_TOGGLE_CROSSHAIR)) // this might change!
+		{
+			switch (input->type)
+			{
+				// enum order from inptport.h may change in future!
+				case IPT_JOYSTICK_UP: //3
+				case IPT_JOYSTICK_DOWN: //4
+				case IPT_JOYSTICK_LEFT: //5
+				case IPT_JOYSTICK_RIGHT: //6
+					c->digital_found = true;
+					if (input->four_way)
+						c->dcontrol_desc[playernum+1] = "joystick (4-way)"; // how to handle localization? l8n
+					else
+						c->dcontrol_desc[playernum+1] = "joystick (8-way)";	// l8n?
+					break;
+				case IPT_JOYSTICKRIGHT_UP: //7
+				case IPT_JOYSTICKRIGHT_DOWN: //8
+				case IPT_JOYSTICKRIGHT_LEFT: //9
+				case IPT_JOYSTICKRIGHT_RIGHT: //10
+				case IPT_JOYSTICKLEFT_UP: //11
+				case IPT_JOYSTICKLEFT_DOWN: //12
+				case IPT_JOYSTICKLEFT_LEFT: //13
+				case IPT_JOYSTICKLEFT_RIGHT: //14
+					c->digital_found = true;
+					if (input->four_way)
+						c->dcontrol_desc[playernum+1] = "double joystick (4-way)";	// l8n?
+					else
+						c->dcontrol_desc[playernum+1] = "double joystick (8-way)";	// l8n?
+					break;
+					
+					// analog
+				case IPT_PADDLE: //26
+					c->analog_found = true;
+					c->acontrol_desc[playernum+1][c->nanalog[playernum+1]] = "paddle";	// l8n?
+					++c->nanalog[playernum+1];
+					break;
+				case IPT_DIAL: //28
+					c->analog_found = true;
+					c->acontrol_desc[playernum+1][c->nanalog[playernum+1]] = "dial";	// l8n?
+					++c->nanalog[playernum+1];
+					break;
+				case IPT_TRACKBALL_X: //30
+					c->analog_found = true;
+					c->acontrol_desc[playernum+1][c->nanalog[playernum+1]] = "trackball";	// l8n?
+					++c->nanalog[playernum+1];
+					break;
+				case IPT_AD_STICK_X: //32
+					c->analog_found = true;
+					c->acontrol_desc[playernum+1][c->nanalog[playernum+1]] = "analog joystick";	// l8n?
+					++c->nanalog[playernum+1];
+					break;
+				case IPT_PEDAL: //37 e.g. gas
+					c->analog_found = true;
+					c->acontrol_desc[playernum+1][c->nanalog[playernum+1]] = "pedal";	// l8n?
+					++c->nanalog[playernum+1];
+					break;
+				case IPT_PEDAL2: //38 e.g. brake
+								 // This must be new, looks like a few games used a player 2 entry
+								 // to describe a second pdedal for p1?? e.g. namcos2 games
+								 // (otherwise it doesn't make sense that player 2 would
+								 //  ONLY have a pedal control...)
+					c->analog_found = true;
+					c->acontrol_desc[playernum+1][c->nanalog[playernum+1]] = "pedal 2";	// l8n?
+					++c->nanalog[playernum];
+					break;
+				case IPT_LIGHTGUN_X: //35
+					c->analog_found = true;
+					c->acontrol_desc[playernum+1][c->nanalog[playernum+1]] = "light gun";	// l8n?
+					++c->nanalog[playernum+1];
+					break;
+					
+					// digital
+				case IPT_BUTTON1: //15
+					c->digital_found = true;
+					if (c->nbutton[playernum+1]<1) c->nbutton[playernum+1] = 1;
+						break;
+				case IPT_BUTTON2: //16
+					c->digital_found = true;
+					if (c->nbutton[playernum+1]<2) c->nbutton[playernum+1] = 2;
+						break;
+				case IPT_BUTTON3: //17
+					c->digital_found = true;
+					if (c->nbutton[playernum+1]<3) c->nbutton[playernum+1] = 3;
+						break;
+				case IPT_BUTTON4: //18
+					c->digital_found = true;
+					if (c->nbutton[playernum+1]<4) c->nbutton[playernum+1] = 4;
+						break;
+				case IPT_BUTTON5: //19
+					c->digital_found = true;
+					if (c->nbutton[playernum+1]<5) c->nbutton[playernum+1] = 5;
+						break;
+				case IPT_BUTTON6: //20
+					c->digital_found = true;
+					if (c->nbutton[playernum+1]<6) c->nbutton[playernum+1] = 6;
+						break;
+				case IPT_BUTTON7: //21
+					c->digital_found = true;
+					if (c->nbutton[playernum+1]<7) c->nbutton[playernum+1] = 7;
+						break;
+				case IPT_BUTTON8: //22
+					c->digital_found = true;
+					if (c->nbutton[playernum+1]<8) c->nbutton[playernum+1] = 8;
+						break;
+				case IPT_BUTTON9: //23
+					c->digital_found = true;
+					if (c->nbutton[playernum+1]<9) c->nbutton[playernum+1] = 9;
+						break;
+				case IPT_BUTTON10: //24
+					c->digital_found = true;
+					if (c->nbutton[playernum+1]<10) c->nbutton[playernum+1] = 10;
+						break;
+					
+					// start buttons
+				case IPT_START1: //40
+					c->digital_found = true;
+					if (c->nstart<1) c->nstart = 1;
+						break;
+				case IPT_START2: //41
+					c->digital_found = true;
+					if (c->nstart<2) c->nstart = 2;
+						break;
+				case IPT_START3: //42
+					c->digital_found = true;
+					if (c->nstart<3) c->nstart = 3;
+						break;
+				case IPT_START4: //43
+					c->digital_found = true;
+					if (c->nstart<4) c->nstart = 4;
+						break;
+				case IPT_START5: //96
+					c->digital_found = true;
+					if (c->nstart<5) c->nstart = 5;
+						break;
+				case IPT_START6: //97
+					c->digital_found = true;
+					if (c->nstart<6) c->nstart = 6;
+						break;
+				case IPT_START7: //98
+					c->digital_found = true;
+					if (c->nstart<7) c->nstart = 7;
+						break;
+				case IPT_START8: //99
+					c->digital_found = true;
+					if (c->nstart<8) c->nstart = 8;
+						break;
+					
+					// coin slots
+				case IPT_COIN1: //44
+					c->other_found = true;
+					if (c->ncoin < 1) c->ncoin = 1;
+						break;
+				case IPT_COIN2: //45
+					c->other_found = true;
+					if (c->ncoin < 2) c->ncoin = 2;
+						break;
+				case IPT_COIN3: //46
+					c->other_found = true;
+					break;
+				case IPT_COIN4: //47
+					c->other_found = true;
+					break;
+				case IPT_COIN5: //100
+					c->other_found = true;
+					break;
+				case IPT_COIN6: //101
+					c->other_found = true;
+					if (c->ncoin < 6) c->ncoin = 6;
+						break;
+				case IPT_COIN7: //102
+					c->other_found = true;
+					if (c->ncoin < 7) c->ncoin = 7;
+						break;
+				case IPT_COIN8: //103
+					c->other_found = true;
+					if (c->ncoin < 8) c->ncoin = 8;
+						break;
+					
+				case IPT_ADJUSTER:
+					c->other_found = true;
+					c->analog_adjuster_found = true;
+					break;
+					// Service "coin"
+				case IPT_SERVICE1: //48
+					c->service_found = true;
+					if (c->ncoin_service < 1) c->ncoin_service = 1;
+						break;
+				case IPT_SERVICE2: //49
+					c->service_found = true;
+					if (c->ncoin_service < 2) c->ncoin_service = 2;
+						break;
+				case IPT_SERVICE3: //50
+					c->service_found = true;
+					if (c->ncoin_service < 3) c->ncoin_service = 3;
+						break;
+				case IPT_SERVICE4: //51
+					c->service_found = true;
+					if (c->ncoin_service < 4) c->ncoin_service = 4;
+						break;
+					
+					// other
+				case IPT_SERVICE: //52
+					c->service_found = true;
+					c->service_switch_found = true;
+					break;
+				case IPT_TILT: //53
+					c->other_found = true;
+					c->tilt_sensor_found = true;
+					break;
+					
+				case IPT_DIPSWITCH_NAME: //54
+					c->service_found = true;
+					++c->ndip;
+					c->dipname[c->ndip] = input->name;
+					break;
+				case IPT_UNKNOWN: //57
+					c->other_found = true;
+					c->nunknown++;
+					break;
+					
+					//case IPT_ANALOG_START:
+					//case IPT_ANALOG_END:
+					//case IPT_EXTENSION:
+					//case IPT_UI_TOGGLE_CROSSHAIR:
+				case 0: //?
+				case IPT_PADDLE_V: //27
+				case IPT_DIAL_V: //29
+				case IPT_TRACKBALL_Y: //31
+				case IPT_AD_STICK_Y: //33
+				case IPT_AD_STICK_Z: //34
+				case IPT_LIGHTGUN_Y: //36
+				case IPT_PORT: //2 what is this item, just a separator like IPT_ANALOG_START?
+				case IPT_DIPSWITCH_SETTING: //55 (use "named" dip-switches instead: IPT_DIPSWITCH_NAME)
+				case IPT_VBLANK: //56
+				case IPT_OSD_RESERVED: //58
+				case IPT_OSD_1: //59
+				case IPT_OSD_2: //60
+				case IPT_OSD_3: //61
+				case IPT_OSD_4: //62
+								// ignore this "control"
+					break;
+				default: // Catch new controls added
+					// Any other control not specifically accounted for in the above cases will be spit out here.
+					// How to lookup a human-readable string value? input->name isn't guaranteed to be available.
+					txtprint("Player %d Other (type=%d)\n", playernum+1, input->type);
+					break;
+			} // end switch
+		} // end if
+		input ++;
+	} //end while
+	end_resource_tracking();
+}
 
-		num = 0;
-		while (in->type != IPT_END)
+
+//===============================================================================
+//  ControlsFormatterInfoPane(struct controls_found inControls)
+//
+//  Takes the data from the controls_found struct which was populated by
+//  the ControlsGetter() function and formats the output for the Hardware Info pane.
+//
+//  The sister function to this is ControlsFormatterReport() in macreports.c,
+//  which does make use of the dipswitch names.
+//===============================================================================
+static void ControlsFormatterInfoPane(controls_found c)
+{
+	//#define ALSO_PRINT_DIPSWITCH_NAMES 1
+
+	// Analog Controls section
+	if (c.analog_found)
 		{
-			if (((in->type & 0xff) > IPT_ANALOG_START) && ((in->type & 0xff) < IPT_ANALOG_END))
+		txtprint ("\nThis game has analog controls:\n");
+		int p = 1;
+		int a = 0;
+		for (p = 1; p <= c.nplayers+1; ++p)
+		{
+			Boolean analog_found = false;
+			for (a = 0; a < c.nanalog[p]; ++a)
 			{
-				int playernum;
-				
 				if (!analog_found)
+					txtprint("Player %d: ", p);
+				// analog control name
+				if (c.acontrol_desc[p][a])
 				{
-					analog_found = 1;
-					txtprint ("\nThis game has analog controls:\n");
+					if (analog_found) txtprint(", ");
+					txtprint("%s", c.acontrol_desc[p][a]);
+					analog_found = true;
+				}
+			}
+			if (analog_found) txtprint("\n"); //next player
+		}
 				}
 				
-				playernum = ((in->type & IPF_PLAYERMASK) >> 16) + 1;
+	// Digital Controls section
+	if (c.digital_found)
+	{
+		txtprint ("\nThis game has digital controls:\n");
+		int p = 1;
+		for (p = 1; p <= c.nplayers+1; ++p)
+		{
+			Boolean digital_found = false;
+			if (c.nbutton[p] || c.dcontrol_desc[p])
+				txtprint("Player %d: ", p);
 				
-				switch (in->type & 0xff)
+			switch (c.nbutton[p])
 				{
-					case IPT_PADDLE:
-						txtprint("Paddle (Player %d)\n", playernum);
+				case 0:
+					//txtprint("(no buttons)");
 						break;
-					case IPT_DIAL:
-						txtprint("Dial (Player %d)\n", playernum);
+				case 1:
+					digital_found = true;
+					txtprint("one button");
 						break;
-					case IPT_TRACKBALL_X:
-						txtprint("Trackball (Player %d)\n", playernum);
+					//case 2: // future localization
+				default:
+					digital_found = true;
+					txtprint("(%d) buttons", c.nbutton[p]);
 						break;
-					case IPT_AD_STICK_X:
-						txtprint("Analog joystick (Player %d)\n", playernum);
+			}
+			// digital joysticks
+			if (c.dcontrol_desc[p])
+			{
+				if (digital_found) txtprint(", ");
+				digital_found = true;
+				txtprint("%s", c.dcontrol_desc[p]);
+			}
+			//else
+			//	txtprint("(no joystick)");
+			if (digital_found) txtprint("\n"); //next player
+		}
+		
+		switch (c.nstart)
+		{
+			case 0:
+				//txtprint("Start buttons: (none)\n");
 						break;
-					case IPT_PEDAL:
-						txtprint("Pedal (Player %d)\n", playernum);
+			case 1:
+				txtprint("Start button: (one)\n");
 						break;
-					case IPT_LIGHTGUN_X:
-						txtprint("Light Gun (Player %d)\n", playernum);
+				//case 2: // future localization
+			default:
+				txtprint("Start buttons: (%d)\n", c.nstart);
 						break;
 				}
 			}
-			in ++;
+	
+	// Other inputs section
+	if (c.other_found)
+	{
+		txtprint("\nOther inputs:\n");
+		if (c.tilt_sensor_found)
+			txtprint("Tilt sensor\n");
+		switch (c.nunknown)
+		{
+			case 0:
+				break;
+			case 1:
+				txtprint("Unknown control: (one)\n");
+				break;
+				//case 2: // future localization
+			default:
+				txtprint("Unknown controls: (%d)\n", c.nunknown);
+				break;
+		}
+		switch (c.ncoin)
+		{
+			case 0:
+				//txtprint("Coin slots: (none)\n");
+				break;
+			case 1:
+				txtprint("Coin slot: (one)\n");
+				break;
+				//case 2: // future localization
+				// http://www.gnu.org/software/gettext/manual/html_node/gettext_150.html
+			default:
+				txtprint("Coin slots: (%d)\n", c.ncoin);
+				break;
+		}
+	}
+
+	// Service inputs section
+	if (c.service_found)
+	{
+		txtprint("\nService inputs:\n");
+		if (c.analog_adjuster_found)
+			txtprint("Analog adjuster\n");
+		if (c.service_switch_found)
+			txtprint("Service switch\n");
+		switch (c.ncoin_service)
+		{
+			case 0:
+				//txtprint("Service coin: (none)\n");
+				break;
+			case 1:
+				txtprint("Service coin: (one)\n");
+				break;
+				//case 2: // future localization
+			default:
+				txtprint("Service coin: (%d)\n", c.ncoin_service);
+				break;
+		}
+		switch (c.ndip)
+		{
+			case 0:
+				//txtprint("Dip-switches: (none)\n");
+				break;
+			case 1:
+				txtprint("Dip-switch: (one)\n");
+				break;
+				//case 2: // future localization
+			default:
+				txtprint("Dip-switches: (%d)\n", c.ndip);
+				break;
+		}
+#ifdef ALSO_PRINT_DIPSWITCH_NAMES
+		// dip-switch names
+		{
+			int p = 1;
+			Boolean dipfound = false;
+			for (p = 1; p <= c.ndip; ++p)
+			{
+				if (dipfound) txtprint(", ");
+				if (c.dipname[p]) {
+					txtprint("%s", c.dipname[p]);
+					dipfound = true;
 		}
-		end_resource_tracking();
 	}
+			if (dipfound) txtprint("\n");
+		}
+#endif /* ALSO_PRINT_DIPSWITCH_NAMES */
+	}
+
 }
 
@@ -2140,7 +2715,7 @@
 		{
 			txtJust(teFlushLeft);
-			txtFont("\pTimes");
+			txtFont("\pMonaco");
 			txtFace(0);
-			txtSize(12);
+			txtSize(9);
 			txtInsert(buf);
 		}
@@ -2185,8 +2760,8 @@
 	txtJust(teFlushLeft);
 	txtFont("\pMonaco");
-	txtFace(bold);
+	txtFace(normal);
 	txtSize(9);
 
-	txtprint("ROMS          %s\n\n",
+	txtprint("%-14s%s\n\n", "ROMS",
 		GetIndCString (rStrings, kInfoStatus, "STATUS"));
 	
