public void ParseNumbers() { // ConsumeInteger() { Substring subs= new Substring(); int result; UT_EQ( false, subs.ConsumeInteger( out result ) ); UT_EQ( 0, result ); subs.Set( "" ); UT_EQ( false, subs.ConsumeInteger( out result ) ); UT_EQ( 0, result ); subs.Set( " ABC" ); UT_EQ( false, subs.ConsumeInteger( out result ) ); UT_EQ( 0, result ); subs.Set( " 12345" ); UT_EQ( true , subs.ConsumeInteger( out result ) ); UT_EQ( 12345, result ); subs.Set( " 12 45" ); UT_EQ( true , subs.ConsumeInteger( out result ) ); UT_EQ( 12, result ); UT_EQ( true , subs.ConsumeInteger( out result ) ); UT_EQ( 45, result ); subs.Set( " 42 ; 7 ; 6 "); UT_EQ( true , subs.ConsumeInteger( out result ) ); UT_EQ( 42, result ); UT_EQ( false, subs.ConsumeInteger( out result ) ); UT_EQ( 0, result ); UT_EQ( false, subs.ConsumeInteger( out result ) ); UT_EQ( 0, result ); char[] ws= " ;".ToCharArray(); subs.Set( " 42 ; 7 ; 6 "); UT_EQ( true , subs.ConsumeInteger( out result, ws ) ); UT_EQ( 42, result ); UT_EQ( true , subs.ConsumeInteger( out result, ws ) ); UT_EQ( 7, result ); UT_EQ( true , subs.ConsumeInteger( out result, ws ) ); UT_EQ( 6, result ); UT_EQ( false, subs.ConsumeInteger( out result, ws ) ); UT_EQ( 0, result ); UT_EQ( false, subs.ConsumeInteger( out result, ws ) ); UT_EQ( 0, result ); } // ConsumeFloat() { Substring subs= new Substring(); double result; UT_EQ( false, subs.ConsumeFloat ( out result ) ); UT_EQ( 0.0, result ); subs.Set( "" ) ; UT_EQ( false, subs.ConsumeFloat ( out result ) ); UT_EQ( 0.0, result ); subs.Set( " ABC" ) ; UT_EQ( false, subs.ConsumeFloat ( out result ) ); UT_EQ( 0.0, result ); subs.Set( " 12345" ) ; UT_EQ( true , subs.ConsumeFloat ( out result ) ); UT_EQ( 12345.0, result ); subs.Set( " 12.45 " ) ; UT_EQ( true , subs.ConsumeFloat ( out result ) ); UT_EQ( 12.45, result ); subs.Set( " 12 45" ) ; UT_EQ( true , subs.ConsumeFloat ( out result ) ); UT_EQ( 12.0, result ); UT_EQ( true , subs.ConsumeFloat ( out result ) ); UT_EQ( 45.0, result ); char[] ws= " ;".ToCharArray(); subs.Set( " 42.3 ; 0.7 ; 6 " ); UT_EQ( true , subs.ConsumeFloat ( out result, null, ws ) ); UT_EQ( 42.3, result ); UT_EQ( true , subs.ConsumeFloat ( out result, null, ws ) ); UT_EQ( 0.7, result ); UT_EQ( true , subs.ConsumeFloat ( out result, null, ws ) ); UT_EQ( 6.0, result ); UT_EQ( false, subs.ConsumeFloat ( out result, null, ws ) ); UT_EQ( 0.0, result ); UT_EQ( false, subs.ConsumeFloat ( out result, null, ws ) ); UT_EQ( 0.0, result ); } }
/** ******************************************************************************************** * Processes the next command found in the format string, by writing formatted information * into the given buffer. * The given Substring holds the next command. When method returns, the command is cut * from the front. * * @param logger The logger that we are embedded in. * @param domain The <em>Log Domain</em>. * @param verbosity The verbosity. This has been checked to be active already on this * stage and is provided to be able to be logged out only. * @param scope Information about the scope of the <em>Log Statement</em>.. * @param dest The buffer to write meta information into. * @param variable The variable to read (may have more characters appended) * * @return The number of tab sequences that were written (by adding ESC::TAB to the buffer). **********************************************************************************************/ protected virtual int processVariable( TextLogger logger, Domain domain, Verbosity verbosity, ScopeInfo scope, AString dest, Substring variable ) { // process commands char c2; switch ( variable.Consume() ) { // scope info case 'S': { // read sub command AString val; switch( c2= variable.Consume() ) { case 'P': // SP: full path { int length; String path= scope.GetFullPath( out length ); if ( length > 0 ) { dest._( path, 0, length ); return 0; } val= NoSourceFileInfo; } break; case 'p': // Sp: trimmed path { val= scope.GetTrimmedPath(); if ( val.IsEmpty() ) val= NoSourceFileInfo; } break; case 'F': // file name { val= scope.GetFileName(); if ( val.IsEmpty() ) val= NoSourceFileInfo; } break; case 'f': // file name without extension { val= scope.GetFileNameWithoutExtension(); if ( val.IsEmpty() ) val= NoSourceFileInfo; } break; case 'M': // method name { String method= scope.GetMethod(); if ( method.Length == 0 ) dest._( NoMethodInfo ); else dest._( method ); return 0; } case 'L': // line number { dest._( scope.GetLineNumber() ); return 0; } default: { if( !warnedOnce ) { warnedOnce= true; ALIB.WARNING( "Unknown format variable '%S" + c2 + "\' (only one warning)" ); } dest._( "%ERROR" ); return 0; } } dest._( val ); return 0; } // %Tx: Time case 'T': { // read sub command c2= variable.Consume(); // %TD: Date if ( c2 == 'D' ) { // get time stamp as DateTime once if ( callerDateTime == null ) callerDateTime= scope.GetTimeStamp().InDotNetDateTime(); // avoid the allocation of a) a StringBuilder (yes, a string builder is allocated inside StringBuilder.AppendFormat!) // and b) a DateTime object, if the format is the unchanged standard. And it is faster anyhow. if ( DateFormat.Equals( "yyyy-MM-dd" ) ) { dest ._( callerDateTime.Value.Year, 4 )._( '-' ) ._( callerDateTime.Value.Month, 2 )._( '-' ) ._( callerDateTime.Value.Day, 2 ); } // support user defined standards else { // detect changes of format string since last log if ( detectDateFormatChanges != DateFormat ) { detectDateFormatChanges= DateFormat; dateFormatString= "{0:" + DateFormat + "}"; } // get date string from system and append to log buffer formatSB.Clear(); formatSB.AppendFormat( CultureInfo.InvariantCulture, dateFormatString, callerDateTime ); dest._( formatSB ); } } // %TT: Time of Day else if ( c2 == 'T' ) { // get time stamp as DateTime once if ( callerDateTime == null ) callerDateTime= scope.GetTimeStamp().InDotNetDateTime(); // avoid the allocation of a) a StringBuilder (yes, a string builder is allocated inside StringBuilder.AppendFormat!) // and b) a DateTime object, if the format is the unchanged standard. And it is faster anyhow. if ( TimeOfDayFormat.Equals( "HH:mm:ss" ) ) { dest ._( callerDateTime.Value.Hour, 2 )._( ':' ) ._( callerDateTime.Value.Minute, 2 )._( ':' ) ._( callerDateTime.Value.Second, 2 ); } // support user defined standards else { // detect changes of format string since last log if ( detectTimeOfDayFormatChanges != TimeOfDayFormat ) { detectTimeOfDayFormatChanges= TimeOfDayFormat; timeOfDayFormatString= "{0:" + TimeOfDayFormat + "}"; } // get time string from system and append to log buffer formatSB.Clear(); formatSB.AppendFormat( CultureInfo.InvariantCulture, timeOfDayFormatString, callerDateTime); dest ._( formatSB ); } } // %TC: Time elapsed since created else if ( c2 == 'C' ) { elapsedTime.Set( scope.GetTimeStamp() ); elapsedTime.Sub( logger.TimeOfCreation ); if( MaxElapsedTime.Raw() < elapsedTime.Raw() ) MaxElapsedTime.Set( elapsedTime ); long maxElapsedSecs= MaxElapsedTime.InSeconds(); TimeSpan elapsed= new TimeSpan( elapsedTime.Raw() ); if ( maxElapsedSecs >= 60*60*24 ) dest._( elapsed.Days )._NC( TimeElapsedDays ); if ( maxElapsedSecs >= 60*60 ) dest._( elapsed.Hours , maxElapsedSecs >= 60*60*10 ? 2 : 1 )._( ':' ); if ( maxElapsedSecs >= 60 ) dest._( elapsed.Minutes, maxElapsedSecs >= 10*60 ? 2 : 1 )._( ':' ); dest._( elapsed.Seconds, maxElapsedSecs > 9 ? 2 : 1 )._NC( '.' ); dest._( elapsed.Milliseconds, 3 ); } // %TL: Time elapsed since last log call else if ( c2 == 'L' ) writeTimeDiff( dest, scope.GetTimeStamp().Since(logger.TimeOfLastLog).InNanos() ); else { if( !warnedOnce ) { warnedOnce= true; ALIB.WARNING( "Unknown format variable '%T" + c2 + "\' (only one warning)" ); } dest._( "%ERROR" ); } return 0; } // thread name / ID case 't': { c2= variable.Consume(); if ( c2 == 'N' ) { dest.Field() ._( scope.GetThreadName() ) .Field( logger.AutoSizes.Next( scope.GetThreadName().Length(), 0 ), Alignment.Center ); } else if ( c2 == 'I' ) { tmpAString._()._( scope.GetThreadID() ); dest.Field() ._( tmpAString ) .Field( logger.AutoSizes.Next( tmpAString .Length(), 0 ), Alignment.Center ); } else { if( !warnedOnce ) { warnedOnce= true; ALIB.WARNING( "Unknown format variable '%t" + c2 + "\' (only one warning)" ); } dest._( "%ERROR" ); } return 0; } case 'L': { c2= variable.Consume(); if ( c2 == 'G' ) dest._NC( logger.GetName() ); else if ( c2 == 'X' ) dest._NC( scope.GetLoxName() ); else { if( !warnedOnce ) { warnedOnce= true; ALIB.WARNING( "Unknown format variable '%L" + c2 + "\' (only one warning)" ); } dest._( "%ERROR" ); return 0; } return 0; } case 'P': { dest._NC( Util.GetProcessName() ); return 0; } case 'V': dest._ ( verbosity == Verbosity.Error ? VerbosityError : verbosity == Verbosity.Warning ? VerbosityWarning : verbosity == Verbosity.Info ? VerbosityInfo : VerbosityVerbose ); return 0; case 'D': { dest.Field()._( domain.FullPath ).Field( logger.AutoSizes.Next( domain.FullPath.Length(), 0 ), Alignment.Left ); return 0; } case '#': dest._( logger.CntLogs, LogNumberMinDigits ); return 0; // A: Auto tab case 'A': { // read extra space from format string int oldStart= variable.Start; int extraSpace; variable.ConsumeInteger( out extraSpace ); if ( oldStart == variable.Start ) extraSpace= 1; // insert ESC code to jump to next tab level extraSpace= Math.Min( extraSpace, 10 + ('Z'-'A') ); char escNo= extraSpace < 10 ? (char) ( '0' + extraSpace ) : (char) ( 'A' + extraSpace ); dest._( "\x1Bt" )._( escNo ); return 1; } default: { if( !warnedOnce ) { warnedOnce= true; ALIB.WARNING( "Unknown format variable \'" + variable.Buf[variable.Start - 1] + "\'" ); } dest._( "%ERROR" ); } return 0; } }
/** **************************************************************************************** * Imports values from the given substring by parsing it. The numbers in the string have * to be separated by ' ' characters (space). * * @param source The Substring that is parsed for the numbers * @param session If \c CurrentData::Clear, which is the default, the current values * are taken from the last session stored and the sessions data is set to 0. * If \c CurrentData::Keep, both, current values and * session values are taken from the string. ******************************************************************************************/ public void Import( Substring source, CurrentData session = CurrentData.Clear ) { Reset(); length= 0; for(;;) { int actStart= source.Start; int value; source.ConsumeInteger( out value ); int lastSession; source.ConsumeInteger( out lastSession ); if ( actStart == source.Start ) break; ensureArraySize( length + 1 ); values [length]= session == CurrentData.Clear ? lastSession : value; sessionValues[length]= session == CurrentData.Clear ? 0 : lastSession; length++; } }