add retro log interface
This commit is contained in:
parent
0a412f779e
commit
ecee3365cc
|
@ -74,6 +74,7 @@
|
|||
<Compile Include="Serializer.cs" />
|
||||
<Compile Include="SettingsUtil.cs" />
|
||||
<Compile Include="SimpleTime.cs" />
|
||||
<Compile Include="Sprintf.cs" />
|
||||
<Compile Include="SwitcherStream.cs" />
|
||||
<Compile Include="UndoHistory.cs" />
|
||||
<Compile Include="UnmanagedResourceHeap.cs" />
|
||||
|
|
|
@ -0,0 +1,668 @@
|
|||
//Richard Prinz, MIT license
|
||||
//http://www.codeproject.com/Articles/19274/A-printf-implementation-in-C
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BizHawk.Common
|
||||
{
|
||||
public static unsafe class Sprintf
|
||||
{
|
||||
#region Public Methods
|
||||
#region IsNumericType
|
||||
/// <summary>
|
||||
/// Determines whether the specified value is of numeric type.
|
||||
/// </summary>
|
||||
/// <param name="o">The object to check.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if o is a numeric type; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public static bool IsNumericType( object o )
|
||||
{
|
||||
return ( o is byte ||
|
||||
o is sbyte ||
|
||||
o is short ||
|
||||
o is ushort ||
|
||||
o is int ||
|
||||
o is uint ||
|
||||
o is long ||
|
||||
o is ulong ||
|
||||
o is float ||
|
||||
o is double ||
|
||||
o is decimal );
|
||||
}
|
||||
#endregion
|
||||
#region IsPositive
|
||||
/// <summary>
|
||||
/// Determines whether the specified value is positive.
|
||||
/// </summary>
|
||||
/// <param name="Value">The value.</param>
|
||||
/// <param name="ZeroIsPositive">if set to <c>true</c> treats 0 as positive.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified value is positive; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public static bool IsPositive( object Value, bool ZeroIsPositive )
|
||||
{
|
||||
switch ( Type.GetTypeCode( Value.GetType() ) )
|
||||
{
|
||||
case TypeCode.SByte:
|
||||
return ( ZeroIsPositive ? (sbyte)Value >= 0 : (sbyte)Value > 0 );
|
||||
case TypeCode.Int16:
|
||||
return ( ZeroIsPositive ? (short)Value >= 0 : (short)Value > 0 );
|
||||
case TypeCode.Int32:
|
||||
return ( ZeroIsPositive ? (int)Value >= 0 : (int)Value > 0 );
|
||||
case TypeCode.Int64:
|
||||
return ( ZeroIsPositive ? (long)Value >= 0 : (long)Value > 0 );
|
||||
case TypeCode.Single:
|
||||
return ( ZeroIsPositive ? (float)Value >= 0 : (float)Value > 0 );
|
||||
case TypeCode.Double:
|
||||
return ( ZeroIsPositive ? (double)Value >= 0 : (double)Value > 0 );
|
||||
case TypeCode.Decimal:
|
||||
return ( ZeroIsPositive ? (decimal)Value >= 0 : (decimal)Value > 0 );
|
||||
case TypeCode.Byte:
|
||||
return ( ZeroIsPositive ? true : (byte)Value > 0 );
|
||||
case TypeCode.UInt16:
|
||||
return ( ZeroIsPositive ? true : (ushort)Value > 0 );
|
||||
case TypeCode.UInt32:
|
||||
return ( ZeroIsPositive ? true : (uint)Value > 0 );
|
||||
case TypeCode.UInt64:
|
||||
return ( ZeroIsPositive ? true : (ulong)Value > 0 );
|
||||
case TypeCode.Char:
|
||||
return ( ZeroIsPositive ? true : (char)Value != '\0' );
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region ToUnsigned
|
||||
/// <summary>
|
||||
/// Converts the specified values boxed type to its correpsonding unsigned
|
||||
/// type.
|
||||
/// </summary>
|
||||
/// <param name="Value">The value.</param>
|
||||
/// <returns>A boxed numeric object whos type is unsigned.</returns>
|
||||
public static object ToUnsigned( object Value )
|
||||
{
|
||||
switch ( Type.GetTypeCode( Value.GetType() ) )
|
||||
{
|
||||
case TypeCode.SByte:
|
||||
return (byte)( (sbyte)Value );
|
||||
case TypeCode.Int16:
|
||||
return (ushort)( (short)Value );
|
||||
case TypeCode.Int32:
|
||||
return (uint)( (int)Value );
|
||||
case TypeCode.Int64:
|
||||
return (ulong)( (long)Value );
|
||||
|
||||
case TypeCode.Byte:
|
||||
return Value;
|
||||
case TypeCode.UInt16:
|
||||
return Value;
|
||||
case TypeCode.UInt32:
|
||||
return Value;
|
||||
case TypeCode.UInt64:
|
||||
return Value;
|
||||
|
||||
case TypeCode.Single:
|
||||
return (UInt32)( (float)Value );
|
||||
case TypeCode.Double:
|
||||
return (ulong)( (double)Value );
|
||||
case TypeCode.Decimal:
|
||||
return (ulong)( (decimal)Value );
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region ToInteger
|
||||
/// <summary>
|
||||
/// Converts the specified values boxed type to its correpsonding integer
|
||||
/// type.
|
||||
/// </summary>
|
||||
/// <param name="Value">The value.</param>
|
||||
/// <returns>A boxed numeric object whos type is an integer type.</returns>
|
||||
public static object ToInteger( object Value, bool Round )
|
||||
{
|
||||
switch ( Type.GetTypeCode( Value.GetType() ) )
|
||||
{
|
||||
case TypeCode.SByte:
|
||||
return Value;
|
||||
case TypeCode.Int16:
|
||||
return Value;
|
||||
case TypeCode.Int32:
|
||||
return Value;
|
||||
case TypeCode.Int64:
|
||||
return Value;
|
||||
|
||||
case TypeCode.Byte:
|
||||
return Value;
|
||||
case TypeCode.UInt16:
|
||||
return Value;
|
||||
case TypeCode.UInt32:
|
||||
return Value;
|
||||
case TypeCode.UInt64:
|
||||
return Value;
|
||||
|
||||
case TypeCode.Single:
|
||||
return ( Round ? (int)Math.Round( (float)Value ) : (int)( (float)Value ) );
|
||||
case TypeCode.Double:
|
||||
return ( Round ? (long)Math.Round( (double)Value ) : (long)( (double)Value ) );
|
||||
case TypeCode.Decimal:
|
||||
return ( Round ? Math.Round( (decimal)Value ) : (decimal)Value );
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region UnboxToLong
|
||||
public static long UnboxToLong( object Value, bool Round )
|
||||
{
|
||||
switch ( Type.GetTypeCode( Value.GetType() ) )
|
||||
{
|
||||
case TypeCode.SByte:
|
||||
return (long)( (sbyte)Value );
|
||||
case TypeCode.Int16:
|
||||
return (long)( (short)Value );
|
||||
case TypeCode.Int32:
|
||||
return (long)( (int)Value );
|
||||
case TypeCode.Int64:
|
||||
return (long)Value;
|
||||
|
||||
case TypeCode.Byte:
|
||||
return (long)( (byte)Value );
|
||||
case TypeCode.UInt16:
|
||||
return (long)( (ushort)Value );
|
||||
case TypeCode.UInt32:
|
||||
return (long)( (uint)Value );
|
||||
case TypeCode.UInt64:
|
||||
return (long)( (ulong)Value );
|
||||
|
||||
case TypeCode.Single:
|
||||
return ( Round ? (long)Math.Round( (float)Value ) : (long)( (float)Value ) );
|
||||
case TypeCode.Double:
|
||||
return ( Round ? (long)Math.Round( (double)Value ) : (long)( (double)Value ) );
|
||||
case TypeCode.Decimal:
|
||||
return ( Round ? (long)Math.Round( (decimal)Value ) : (long)( (decimal)Value ) );
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region ReplaceMetaChars
|
||||
/// <summary>
|
||||
/// Replaces the string representations of meta chars with their corresponding
|
||||
/// character values.
|
||||
/// </summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <returns>A string with all string meta chars are replaced</returns>
|
||||
public static string ReplaceMetaChars( string input )
|
||||
{
|
||||
return Regex.Replace( input, @"(\\)(\d{3}|[^\d])?", new MatchEvaluator( ReplaceMetaCharsMatch ) );
|
||||
}
|
||||
private static string ReplaceMetaCharsMatch( Match m )
|
||||
{
|
||||
// convert octal quotes (like \040)
|
||||
if ( m.Groups[2].Length == 3 )
|
||||
return Convert.ToChar( Convert.ToByte( m.Groups[2].Value, 8 ) ).ToString();
|
||||
else
|
||||
{
|
||||
// convert all other special meta characters
|
||||
//TODO: \xhhh hex and possible dec !!
|
||||
switch ( m.Groups[2].Value )
|
||||
{
|
||||
case "0": // null
|
||||
return "\0";
|
||||
case "a": // alert (beep)
|
||||
return "\a";
|
||||
case "b": // BS
|
||||
return "\b";
|
||||
case "f": // FF
|
||||
return "\f";
|
||||
case "v": // vertical tab
|
||||
return "\v";
|
||||
case "r": // CR
|
||||
return "\r";
|
||||
case "n": // LF
|
||||
return "\n";
|
||||
case "t": // Tab
|
||||
return "\t";
|
||||
default:
|
||||
// if neither an octal quote nor a special meta character
|
||||
// so just remove the backslash
|
||||
return m.Groups[2].Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region sprintf
|
||||
public static string sprintf( string Format, Func<IntPtr> fetcher )
|
||||
{
|
||||
#region Variables
|
||||
StringBuilder f = new StringBuilder();
|
||||
Regex r = new Regex( @"\%(\d*\$)?([\'\#\-\+ ]*)(\d*)(?:\.(\d+))?([hl])?([dioxXucsfeEgGpn%])" );
|
||||
//"%[parameter][flags][width][.precision][length]type"
|
||||
Match m = null;
|
||||
string w = String.Empty;
|
||||
int defaultParamIx = 0;
|
||||
int paramIx;
|
||||
object o = null;
|
||||
|
||||
bool flagLeft2Right = false;
|
||||
bool flagAlternate = false;
|
||||
bool flagPositiveSign = false;
|
||||
bool flagPositiveSpace = false;
|
||||
bool flagZeroPadding = false;
|
||||
bool flagGroupThousands = false;
|
||||
|
||||
int fieldLength = 0;
|
||||
int fieldPrecision = 0;
|
||||
char shortLongIndicator = '\0';
|
||||
char formatSpecifier = '\0';
|
||||
char paddingCharacter = ' ';
|
||||
#endregion
|
||||
|
||||
// find all format parameters in format string
|
||||
f.Append( Format );
|
||||
m = r.Match( f.ToString() );
|
||||
while ( m.Success )
|
||||
{
|
||||
#region parameter index
|
||||
paramIx = defaultParamIx;
|
||||
if ( m.Groups[1] != null && m.Groups[1].Value.Length > 0 )
|
||||
{
|
||||
string val = m.Groups[1].Value.Substring( 0, m.Groups[1].Value.Length - 1 );
|
||||
paramIx = Convert.ToInt32( val ) - 1;
|
||||
};
|
||||
#endregion
|
||||
|
||||
#region format flags
|
||||
// extract format flags
|
||||
flagAlternate = false;
|
||||
flagLeft2Right = false;
|
||||
flagPositiveSign = false;
|
||||
flagPositiveSpace = false;
|
||||
flagZeroPadding = false;
|
||||
flagGroupThousands = false;
|
||||
if ( m.Groups[2] != null && m.Groups[2].Value.Length > 0 )
|
||||
{
|
||||
string flags = m.Groups[2].Value;
|
||||
|
||||
flagAlternate = ( flags.IndexOf( '#' ) >= 0 );
|
||||
flagLeft2Right = ( flags.IndexOf( '-' ) >= 0 );
|
||||
flagPositiveSign = ( flags.IndexOf( '+' ) >= 0 );
|
||||
flagPositiveSpace = ( flags.IndexOf( ' ' ) >= 0 );
|
||||
flagGroupThousands = ( flags.IndexOf( '\'' ) >= 0 );
|
||||
|
||||
// positive + indicator overrides a
|
||||
// positive space character
|
||||
if ( flagPositiveSign && flagPositiveSpace )
|
||||
flagPositiveSpace = false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region field length
|
||||
// extract field length and
|
||||
// pading character
|
||||
paddingCharacter = ' ';
|
||||
fieldLength = int.MinValue;
|
||||
if ( m.Groups[3] != null && m.Groups[3].Value.Length > 0 )
|
||||
{
|
||||
fieldLength = Convert.ToInt32( m.Groups[3].Value );
|
||||
flagZeroPadding = ( m.Groups[3].Value[0] == '0' );
|
||||
}
|
||||
#endregion
|
||||
|
||||
if ( flagZeroPadding )
|
||||
paddingCharacter = '0';
|
||||
|
||||
// left2right allignment overrides zero padding
|
||||
if ( flagLeft2Right && flagZeroPadding )
|
||||
{
|
||||
flagZeroPadding = false;
|
||||
paddingCharacter = ' ';
|
||||
}
|
||||
|
||||
#region field precision
|
||||
// extract field precision
|
||||
fieldPrecision = int.MinValue;
|
||||
if ( m.Groups[4] != null && m.Groups[4].Value.Length > 0 )
|
||||
fieldPrecision = Convert.ToInt32( m.Groups[4].Value );
|
||||
#endregion
|
||||
|
||||
#region short / long indicator
|
||||
// extract short / long indicator
|
||||
shortLongIndicator = Char.MinValue;
|
||||
if ( m.Groups[5] != null && m.Groups[5].Value.Length > 0 )
|
||||
shortLongIndicator = m.Groups[5].Value[0];
|
||||
#endregion
|
||||
|
||||
#region format specifier
|
||||
// extract format
|
||||
formatSpecifier = Char.MinValue;
|
||||
if ( m.Groups[6] != null && m.Groups[6].Value.Length > 0 )
|
||||
formatSpecifier = m.Groups[6].Value[0];
|
||||
#endregion
|
||||
|
||||
// default precision is 6 digits if none is specified except
|
||||
if ( fieldPrecision == int.MinValue &&
|
||||
formatSpecifier != 's' &&
|
||||
formatSpecifier != 'c' &&
|
||||
Char.ToUpper( formatSpecifier ) != 'X' &&
|
||||
formatSpecifier != 'o' )
|
||||
fieldPrecision = 6;
|
||||
|
||||
#region get next value parameter
|
||||
IntPtr n = fetcher();
|
||||
// get next value parameter and convert value parameter depending on short / long indicator
|
||||
//if ( Parameters == null || paramIx >= Parameters.Length )
|
||||
// o = null;
|
||||
//else
|
||||
{
|
||||
if (shortLongIndicator == 'h')
|
||||
{
|
||||
o = (short)(n.ToInt32());
|
||||
}
|
||||
else if (shortLongIndicator == 'l')
|
||||
{
|
||||
//zero 08-nov-2015 - something like this for longs, but i dont think this is a long
|
||||
//o = n.ToInt32() + (((long)(fetcher().ToInt32()) << 32));
|
||||
throw new InvalidOperationException("horn-rimmed astatine embryology");
|
||||
}
|
||||
else o = n.ToInt32();
|
||||
}
|
||||
#endregion
|
||||
|
||||
// convert value parameters to a string depending on the formatSpecifier
|
||||
w = String.Empty;
|
||||
switch ( formatSpecifier )
|
||||
{
|
||||
#region % - character
|
||||
case '%': // % character
|
||||
w = "%";
|
||||
break;
|
||||
#endregion
|
||||
#region d - integer
|
||||
case 'd': // integer
|
||||
w = FormatNumber( ( flagGroupThousands ? "n" : "d" ), flagAlternate,
|
||||
fieldLength, int.MinValue, flagLeft2Right,
|
||||
flagPositiveSign, flagPositiveSpace,
|
||||
paddingCharacter, o );
|
||||
defaultParamIx++;
|
||||
break;
|
||||
#endregion
|
||||
#region i - integer
|
||||
case 'i': // integer
|
||||
goto case 'd';
|
||||
#endregion
|
||||
#region o - octal integer
|
||||
case 'o': // octal integer - no leading zero
|
||||
w = FormatOct( "o", flagAlternate,
|
||||
fieldLength, int.MinValue, flagLeft2Right,
|
||||
paddingCharacter, o );
|
||||
defaultParamIx++;
|
||||
break;
|
||||
#endregion
|
||||
#region x - hex integer
|
||||
case 'x': // hex integer - no leading zero
|
||||
w = FormatHex( "x", flagAlternate,
|
||||
fieldLength, fieldPrecision, flagLeft2Right,
|
||||
paddingCharacter, o );
|
||||
defaultParamIx++;
|
||||
break;
|
||||
#endregion
|
||||
#region X - hex integer
|
||||
case 'X': // same as x but with capital hex characters
|
||||
w = FormatHex( "X", flagAlternate,
|
||||
fieldLength, fieldPrecision, flagLeft2Right,
|
||||
paddingCharacter, o );
|
||||
defaultParamIx++;
|
||||
break;
|
||||
#endregion
|
||||
#region u - unsigned integer
|
||||
case 'u': // unsigned integer
|
||||
w = FormatNumber( ( flagGroupThousands ? "n" : "d" ), flagAlternate,
|
||||
fieldLength, int.MinValue, flagLeft2Right,
|
||||
false, false,
|
||||
paddingCharacter, ToUnsigned( o ) );
|
||||
defaultParamIx++;
|
||||
break;
|
||||
#endregion
|
||||
#region c - character
|
||||
case 'c': // character
|
||||
w = ((char)(n.ToInt32())).ToString();
|
||||
defaultParamIx++;
|
||||
break;
|
||||
#endregion
|
||||
#region s - string
|
||||
case 's': // string
|
||||
string t = "{0" + ( fieldLength != int.MinValue ? "," + ( flagLeft2Right ? "-" : String.Empty ) + fieldLength.ToString() : String.Empty ) + ":s}";
|
||||
w = Marshal.PtrToStringAnsi(n);
|
||||
if ( fieldPrecision >= 0 )
|
||||
w = w.Substring( 0, fieldPrecision );
|
||||
|
||||
if ( fieldLength != int.MinValue )
|
||||
if ( flagLeft2Right )
|
||||
w = w.PadRight( fieldLength, paddingCharacter );
|
||||
else
|
||||
w = w.PadLeft( fieldLength, paddingCharacter );
|
||||
defaultParamIx++;
|
||||
break;
|
||||
#endregion
|
||||
#region f - double number
|
||||
case 'f': // double
|
||||
throw new InvalidOperationException("cataleptic kangaroo orchestra");
|
||||
//w = FormatNumber( ( flagGroupThousands ? "n" : "f" ), flagAlternate,
|
||||
// fieldLength, fieldPrecision, flagLeft2Right,
|
||||
// flagPositiveSign, flagPositiveSpace,
|
||||
// paddingCharacter, o );
|
||||
//defaultParamIx++;
|
||||
//break;
|
||||
#endregion
|
||||
#region e - exponent number
|
||||
case 'e': // double / exponent
|
||||
throw new InvalidOperationException("cataleptic kangaroo orchestra");
|
||||
//w = FormatNumber( "e", flagAlternate,
|
||||
// fieldLength, fieldPrecision, flagLeft2Right,
|
||||
// flagPositiveSign, flagPositiveSpace,
|
||||
// paddingCharacter, o );
|
||||
//defaultParamIx++;
|
||||
//break;
|
||||
#endregion
|
||||
#region E - exponent number
|
||||
case 'E': // double / exponent
|
||||
throw new InvalidOperationException("cataleptic kangaroo orchestra");
|
||||
//w = FormatNumber( "E", flagAlternate,
|
||||
// fieldLength, fieldPrecision, flagLeft2Right,
|
||||
// flagPositiveSign, flagPositiveSpace,
|
||||
// paddingCharacter, o );
|
||||
//defaultParamIx++;
|
||||
//break;
|
||||
#endregion
|
||||
#region g - general number
|
||||
case 'g': // double / exponent
|
||||
throw new InvalidOperationException("cataleptic kangaroo orchestra");
|
||||
//w = FormatNumber( "g", flagAlternate,
|
||||
// fieldLength, fieldPrecision, flagLeft2Right,
|
||||
// flagPositiveSign, flagPositiveSpace,
|
||||
// paddingCharacter, o );
|
||||
//defaultParamIx++;
|
||||
//break;
|
||||
#endregion
|
||||
#region G - general number
|
||||
case 'G': // double / exponent
|
||||
throw new InvalidOperationException("cataleptic kangaroo orchestra");
|
||||
//w = FormatNumber( "G", flagAlternate,
|
||||
// fieldLength, fieldPrecision, flagLeft2Right,
|
||||
// flagPositiveSign, flagPositiveSpace,
|
||||
// paddingCharacter, o );
|
||||
//defaultParamIx++;
|
||||
//break;
|
||||
#endregion
|
||||
#region p - pointer
|
||||
case 'p': // pointer
|
||||
if ( o is IntPtr )
|
||||
w = "0x" + n.ToString( "x" );
|
||||
defaultParamIx++;
|
||||
break;
|
||||
#endregion
|
||||
#region n - number of processed chars so far
|
||||
case 'n': // number of characters so far
|
||||
w = FormatNumber( "d", flagAlternate,
|
||||
fieldLength, int.MinValue, flagLeft2Right,
|
||||
flagPositiveSign, flagPositiveSpace,
|
||||
paddingCharacter, m.Index );
|
||||
break;
|
||||
#endregion
|
||||
default:
|
||||
w = String.Empty;
|
||||
defaultParamIx++;
|
||||
break;
|
||||
}
|
||||
|
||||
// replace format parameter with parameter value
|
||||
// and start searching for the next format parameter
|
||||
// AFTER the position of the current inserted value
|
||||
// to prohibit recursive matches if the value also
|
||||
// includes a format specifier
|
||||
f.Remove( m.Index, m.Length );
|
||||
f.Insert( m.Index, w );
|
||||
m = r.Match( f.ToString(), m.Index + w.Length );
|
||||
}
|
||||
|
||||
return f.ToString();
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
#region FormatOCT
|
||||
private static string FormatOct( string NativeFormat, bool Alternate,
|
||||
int FieldLength, int FieldPrecision,
|
||||
bool Left2Right,
|
||||
char Padding, object Value )
|
||||
{
|
||||
string w = String.Empty;
|
||||
string lengthFormat = "{0" + ( FieldLength != int.MinValue ?
|
||||
"," + ( Left2Right ?
|
||||
"-" :
|
||||
String.Empty ) + FieldLength.ToString() :
|
||||
String.Empty ) + "}";
|
||||
|
||||
if ( IsNumericType( Value ) )
|
||||
{
|
||||
w = Convert.ToString( UnboxToLong( Value, true ), 8 );
|
||||
|
||||
if ( Left2Right || Padding == ' ' )
|
||||
{
|
||||
if ( Alternate && w != "0" )
|
||||
w = "0" + w;
|
||||
w = String.Format( lengthFormat, w );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( FieldLength != int.MinValue )
|
||||
w = w.PadLeft( FieldLength - ( Alternate && w != "0" ? 1 : 0 ), Padding );
|
||||
if ( Alternate && w != "0" )
|
||||
w = "0" + w;
|
||||
}
|
||||
}
|
||||
|
||||
return w;
|
||||
}
|
||||
#endregion
|
||||
#region FormatHEX
|
||||
private static string FormatHex( string NativeFormat, bool Alternate,
|
||||
int FieldLength, int FieldPrecision,
|
||||
bool Left2Right,
|
||||
char Padding, object Value )
|
||||
{
|
||||
string w = String.Empty;
|
||||
string lengthFormat = "{0" + ( FieldLength != int.MinValue ?
|
||||
"," + ( Left2Right ?
|
||||
"-" :
|
||||
String.Empty ) + FieldLength.ToString() :
|
||||
String.Empty ) + "}";
|
||||
string numberFormat = "{0:" + NativeFormat + ( FieldPrecision != int.MinValue ?
|
||||
FieldPrecision.ToString() :
|
||||
String.Empty ) + "}";
|
||||
|
||||
if ( IsNumericType( Value ) )
|
||||
{
|
||||
w = String.Format( numberFormat, Value );
|
||||
|
||||
if ( Left2Right || Padding == ' ' )
|
||||
{
|
||||
if ( Alternate )
|
||||
w = ( NativeFormat == "x" ? "0x" : "0X" ) + w;
|
||||
w = String.Format( lengthFormat, w );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( FieldLength != int.MinValue )
|
||||
w = w.PadLeft( FieldLength - ( Alternate ? 2 : 0 ), Padding );
|
||||
if ( Alternate )
|
||||
w = ( NativeFormat == "x" ? "0x" : "0X" ) + w;
|
||||
}
|
||||
}
|
||||
|
||||
return w;
|
||||
}
|
||||
#endregion
|
||||
#region FormatNumber
|
||||
private static string FormatNumber( string NativeFormat, bool Alternate,
|
||||
int FieldLength, int FieldPrecision,
|
||||
bool Left2Right,
|
||||
bool PositiveSign, bool PositiveSpace,
|
||||
char Padding, object Value )
|
||||
{
|
||||
string w = String.Empty;
|
||||
string lengthFormat = "{0" + ( FieldLength != int.MinValue ?
|
||||
"," + ( Left2Right ?
|
||||
"-" :
|
||||
String.Empty ) + FieldLength.ToString() :
|
||||
String.Empty ) + "}";
|
||||
string numberFormat = "{0:" + NativeFormat + ( FieldPrecision != int.MinValue ?
|
||||
FieldPrecision.ToString() :
|
||||
"0" ) + "}";
|
||||
|
||||
if ( IsNumericType( Value ) )
|
||||
{
|
||||
w = String.Format( numberFormat, Value );
|
||||
|
||||
if ( Left2Right || Padding == ' ' )
|
||||
{
|
||||
if ( IsPositive( Value, true ) )
|
||||
w = ( PositiveSign ?
|
||||
"+" : ( PositiveSpace ? " " : String.Empty ) ) + w;
|
||||
w = String.Format( lengthFormat, w );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( w.StartsWith( "-" ) )
|
||||
w = w.Substring( 1 );
|
||||
if ( FieldLength != int.MinValue )
|
||||
w = w.PadLeft( FieldLength - 1, Padding );
|
||||
if ( IsPositive( Value, true ) )
|
||||
w = ( PositiveSign ?
|
||||
"+" : ( PositiveSpace ?
|
||||
" " : ( FieldLength != int.MinValue ?
|
||||
Padding.ToString() : String.Empty ) ) ) + w;
|
||||
else
|
||||
w = "-" + w;
|
||||
}
|
||||
}
|
||||
|
||||
return w;
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -8,7 +8,7 @@ using System.Reflection;
|
|||
|
||||
namespace BizHawk.Common
|
||||
{
|
||||
public static unsafe class Util
|
||||
public static unsafe partial class Util
|
||||
{
|
||||
public static void CopyStream(Stream src, Stream dest, long len)
|
||||
{
|
||||
|
|
|
@ -48,6 +48,16 @@ namespace BizHawk.Emulation.Cores
|
|||
R3 = 15
|
||||
};
|
||||
|
||||
public enum RETRO_LOG_LEVEL : int //exact type size is unclear
|
||||
{
|
||||
DEBUG = 0,
|
||||
INFO,
|
||||
WARN,
|
||||
ERROR,
|
||||
|
||||
DUMMY = Int32.MaxValue
|
||||
};
|
||||
|
||||
public enum RETRO_DEVICE_ID_ANALOG
|
||||
{
|
||||
// LEFT / RIGHT?
|
||||
|
@ -436,6 +446,8 @@ namespace BizHawk.Emulation.Cores
|
|||
|
||||
#region callback prototypes
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public unsafe delegate void retro_log_printf_t(RETRO_LOG_LEVEL level, string fmt, IntPtr a0, IntPtr a1, IntPtr a2, IntPtr a3, IntPtr a4, IntPtr a5, IntPtr a6, IntPtr a7, IntPtr a8, IntPtr a9, IntPtr a10, IntPtr a11, IntPtr a12, IntPtr a13, IntPtr a14, IntPtr a15);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
[return:MarshalAs(UnmanagedType.U1)]
|
||||
public delegate bool retro_environment_t(RETRO_ENVIRONMENT cmd, IntPtr data);
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
|
|
|
@ -87,6 +87,15 @@ namespace BizHawk.Emulation.Cores
|
|||
|
||||
#region callbacks
|
||||
|
||||
unsafe void retro_log_printf(LibRetro.RETRO_LOG_LEVEL level, string fmt, IntPtr a0, IntPtr a1, IntPtr a2, IntPtr a3, IntPtr a4, IntPtr a5, IntPtr a6, IntPtr a7, IntPtr a8, IntPtr a9, IntPtr a10, IntPtr a11, IntPtr a12, IntPtr a13, IntPtr a14, IntPtr a15)
|
||||
{
|
||||
//avert your eyes, these things were not meant to be seen in c#
|
||||
//I'm not sure this is a great idea. It would suck for silly logging to be unstable. But.. I dont think this is unstable. The sprintf might just print some garbledy stuff.
|
||||
var args = new IntPtr[] { a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 };
|
||||
int idx = 0;
|
||||
Console.Write(Sprintf.sprintf(fmt, () => args[idx++]));
|
||||
}
|
||||
|
||||
unsafe bool retro_environment(LibRetro.RETRO_ENVIRONMENT cmd, IntPtr data)
|
||||
{
|
||||
Console.WriteLine(cmd);
|
||||
|
@ -199,7 +208,8 @@ namespace BizHawk.Emulation.Cores
|
|||
case LibRetro.RETRO_ENVIRONMENT.GET_INPUT_DEVICE_CAPABILITIES:
|
||||
return false;
|
||||
case LibRetro.RETRO_ENVIRONMENT.GET_LOG_INTERFACE:
|
||||
return false;
|
||||
*(IntPtr*)data = Marshal.GetFunctionPointerForDelegate(retro_log_printf_cb);
|
||||
return true;
|
||||
case LibRetro.RETRO_ENVIRONMENT.GET_PERF_INTERFACE:
|
||||
//some builds of fmsx core crash without this set
|
||||
Marshal.StructureToPtr(retro_perf_callback, data, false);
|
||||
|
@ -295,6 +305,7 @@ namespace BizHawk.Emulation.Cores
|
|||
LibRetro.retro_audio_sample_batch_t retro_audio_sample_batch_cb;
|
||||
LibRetro.retro_input_poll_t retro_input_poll_cb;
|
||||
LibRetro.retro_input_state_t retro_input_state_cb;
|
||||
LibRetro.retro_log_printf_t retro_log_printf_cb;
|
||||
|
||||
LibRetro.retro_perf_callback retro_perf_callback = new LibRetro.retro_perf_callback();
|
||||
|
||||
|
@ -388,6 +399,7 @@ namespace BizHawk.Emulation.Cores
|
|||
retro_audio_sample_batch_cb = new LibRetro.retro_audio_sample_batch_t(retro_audio_sample_batch);
|
||||
retro_input_poll_cb = new LibRetro.retro_input_poll_t(retro_input_poll);
|
||||
retro_input_state_cb = new LibRetro.retro_input_state_t(retro_input_state);
|
||||
retro_log_printf_cb = new LibRetro.retro_log_printf_t(retro_log_printf);
|
||||
|
||||
//no way (need new mechanism) to check for SSSE3, MMXEXT, SSE4, SSE42
|
||||
retro_perf_callback.get_cpu_features = new LibRetro.retro_get_cpu_features_t(() => (ulong)(
|
||||
|
|
Loading…
Reference in New Issue