/** **************************************************************************************** * 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++; } }
/** ******************************************************************************************** * 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') { // create TimeSpan object (on the stack by using new! :) TimeSpan elapsed = new TimeSpan(scope.GetTimeStamp().Raw() - logger.TimeOfCreation.Raw()); if (elapsed.Days > 0) { dest._(elapsed.Days)._(TimeElapsedDays); } if (elapsed.Hours > 0) { dest._(elapsed.Hours)._(':'); } dest._(elapsed.Minutes, 2)._(':') ._(elapsed.Seconds, 2)._('.') ._(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); } }
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); } }