/** ******************************************************************************************** * Searches a domain. If not found, the domain is (or path of domains are) created in * the domain tree. * If the path string starts with the character defined in #PathSeparator, then * the search (and creation) is done starting from the root domain of this domain and not * from this domain. * * @param domainPathAS Path and domain to search. * @param sensitivity Denotes if domain name search is treated case sensitive or not. * @param maxCreate The maximum number of sub domains that are created if not * found at the end of the path. * @param[out] wasCreated Output parameter that is set \c true if domain was not found * and hence created. * @return The domain found or created. **********************************************************************************************/ public Domain Find(AString domainPathAS, Case sensitivity, int maxCreate, ref bool wasCreated) { Substring domainPath = tSubstring; domainPath.Set(domainPathAS); // set optional output parameter as default to false wasCreated = false; int lenBeforeTrim = domainPath.Length(); // if string is empty (resp. contains only separator characters), return ourselves while (domainPath.Consume(PathSeparator)) { ; } if (domainPath.IsEmpty()) { return(this); } // Trailing domain separator found: call find on root domain Domain startDomain = this; if (lenBeforeTrim > domainPath.Length()) { while (startDomain.Parent != null) { startDomain = startDomain.Parent; } } // call find return(startDomain.findRecursive(domainPath, sensitivity, maxCreate, ref wasCreated)); }
bool Get(Object category, Object name, AString target) { // assemble option name as CATEGORY_NAME target.Clear()._(category); if (target.IsNotEmpty()) { target._('_'); } target._(name); int optionLength = target.Length(); Substring actVar = new Substring(); for (int i = 0; i < args.Length; i++) { // remove whitespaces (if somebody would work with quotation marks...) actVar.Set(args[i]).Trim(); // request '-' and allow a second '-' if (!actVar.Consume('-')) { continue; } actVar.Consume('-'); if (target.CompareTo(args[i], Case.Ignore, actVar.Start, optionLength, 0, optionLength) == 0) { //again, lets trim before searching the = sign (really almost unnecessary) actVar.Start += optionLength; if (actVar.Consume('=', Whitespaces.Trim)) { actVar.TrimStart(); actVar.TrimEnd(); target.Clear(); target._NC(args[i], actVar.Start, actVar.Length()); return(true); } } } return(false); }
/** ******************************************************************************************** * 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); } }
// ############################################################################################# // logText // ############################################################################################# /** ******************************************************************************************** * * The implementation of the abstract method of parent class TextLogger. Logs messages to the * application console and/or the VStudio output window. * * @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 msg The log message * @param scope Information about the scope of the <em>Log Statement</em>.. * @param lineNumber The line number of a multi-line message, starting with 0. For * single line messages this is -1. **********************************************************************************************/ override protected void logText(Domain domain, Verbosity verbosity, AString msg, ScopeInfo scope, int lineNumber) { // loop over message, print the parts between the escape sequences Tokenizer msgParts = new Tokenizer(msg, '\x001B'); Substring actual = msgParts.Actual; Substring rest = msgParts.Rest; int column = 0; for (;;) { msgParts.Next(Whitespaces.Keep); // check if this is an ANSI sequence already if (rest.CharAtStart() == '[') { // read the 'm' int idx = rest.IndexOf('m'); if (idx < 0) // unknown ANSI Code { ALIB.WARNING("Unknown ANSI ESC Code "); textWriter.Write(actual.Buf, actual.Start, actual.Length()); continue; } column += actual.Length(); actual.End = rest.Start + idx; rest.Start += idx + 1; textWriter.Write(actual.Buf, actual.Start, actual.Length()); continue; } else { if (actual.IsNotEmpty()) { textWriter.Write(actual.Buf, actual.Start, actual.Length()); column += actual.Length(); } } // end of loop? if (!msgParts.HasNext()) { break; } // found an ESC sequence char c = rest.Consume(); // Colors bool isForeGround = true; if (c == 'C' || c == 'c') { isForeGround = c == 'c'; c = rest.Consume(); int colNo = c - '0'; ALIB.ASSERT_WARNING(colNo >= 0 && colNo <= 9, "Unknown ESC-c code"); // add bg colNo += isForeGround ? 0 : 10; // add light colNo += (isForeGround ? !IsBackgroundLight : IsBackgroundLight) ? 20 : 0; textWriter.Write(ansiCols[colNo]); } // Styles else if (c == 's') { // bold/italics style not supported in Windows console // reset all if (rest.Consume() == 'a') { textWriter.Write(ANSI_RESET); } } // auto tab / end of meta else if (c == 't' || c == 'A') { bool endOfMeta = c == 'A'; c = rest.Consume(); int extraSpace = c >= '0' && c <= '9' ? (int)(c - '0') : (int)(c - 'A') + 10; int tabStop = AutoSizes.Next(column, extraSpace); Util.WriteSpaces(textWriter, tabStop - column); column = tabStop; if (endOfMeta) { String msgPrefix; switch (verbosity) { case lox.Verbosity.Verbose: msgPrefix = MsgPrefixVerbose; break; case lox.Verbosity.Info: msgPrefix = MsgPrefixInfo; break; case lox.Verbosity.Warning: msgPrefix = MsgPrefixWarning; break; case lox.Verbosity.Error: msgPrefix = MsgPrefixError; break; default: msgPrefix = ""; break; } textWriter.Write(msgPrefix); } } // Link (we just colorize links here) else if (c == 'l') { textWriter.Write(rest.Consume() == 'S' ? (IsBackgroundLight ? ANSI_LIGHT_BLUE : ANSI_LIGHT_BLUE) : ANSI_STD_COL); } else { ALIB.WARNING("Unknown ESC code"); } } // write loop textWriter.WriteLine(MsgSuffix); }
// ############################################################################################# // Internals // ############################################################################################# /** **************************************************************************************** * Internal, recursive helper of #Find. * * @param domainPath Path to search. * @param sensitivity Denotes if domain name search is treated case sensitive or not. * @param maxCreate The maximum number of sub domains that are created if not * found at the end of the path. * @param[out] wasCreated Output parameter that is set \c true if domain was not found * and hence created. * @return The domain found or created. ******************************************************************************************/ protected Domain findRecursive(Substring domainPath, Case sensitivity, int maxCreate, ref bool wasCreated) { //--- get act sub-name and rest of path domainPath.Consume(PathSeparator); int endSubName = domainPath.IndexOf(PathSeparator); ALIB.ASSERT_ERROR(endSubName != 0, "Internal Error"); // find end of actual domain name and save rest Substring restOfDomainPath = tSubstring2; restOfDomainPath.SetNull(); if (endSubName > 0) { domainPath.Split(endSubName, restOfDomainPath, 1); } // search sub-domain Domain subDomain = null; // "." if (domainPath.Equals(".")) { subDomain = this; } // ".." else if (domainPath.Equals("..")) { subDomain = Parent != null ? Parent : this; } // search in sub-domain else { int i; bool fixedOnce = false; for (;;) { for (i = 0; i < SubDomains.Count; i++) { int comparison = SubDomains[i].Name.CompareTo(domainPath, sensitivity); if (comparison >= 0) { if (comparison == 0) { subDomain = SubDomains[i]; } break; } } // domain found? if (subDomain != null) { break; } // try and fix name if (!fixedOnce) { fixedOnce = true; bool illegalCharacterFound = false; for (int cp = 0; cp < domainPath.Length(); ++cp) { char c = domainPath.CharAt(cp); if (c < '-' || c > 'z' || c == '<' || c == '>' || c == '[' || c == ']' || c == '=' || c == '?' || c == ';' || c == ':' || c == '\\' || c == '\'' || c == '.' || c == ',' ) { illegalCharacterFound = true; domainPath.Buf[domainPath.Start + cp] = '#'; } } if (illegalCharacterFound) { continue; } } // create if (maxCreate == 0) { return(null); } wasCreated = true; SubDomains.Insert(i, subDomain = new Domain(this, new AString(domainPath))); maxCreate--; if (maxCreate == 0) { return(subDomain); } break; } } // recursion? if (restOfDomainPath.IsNotEmpty()) { domainPath.Set(restOfDomainPath); return(subDomain.findRecursive(domainPath, sensitivity, maxCreate, ref wasCreated)); } // that's it return(subDomain); }
public void Consume() { // null substring { Substring s = new Substring(); Substring r = new Substring("oldval"); UT_EQ('\0', s.Consume( )); UT_EQ(0, s.Consume(0, r)); UT_TRUE(r.IsNull()); UT_EQ(0, s.Consume(5, r)); UT_TRUE(r.IsNull()); UT_EQ(false, s.Consume('a')); UT_EQ(false, s.Consume("word")); UT_EQ('\0', s.ConsumeFromEnd( )); UT_EQ(0, s.ConsumeFromEnd(0)); UT_EQ(0, s.ConsumeFromEnd(5)); UT_EQ(false, s.ConsumeFromEnd('a')); UT_EQ(false, s.ConsumeFromEnd("word")); } // empty substring { Substring s = new Substring("aaaaaaaaaaaa"); Substring r = new Substring("oldval"); s.Start = 5; s.End = 4; UT_EQ('\0', s.Consume( )); UT_EQ(0, s.Consume(0, r)); UT_TRUE(r.IsNotNull()); UT_TRUE(r.IsEmpty()); UT_EQ(0, s.Consume(5, r)); UT_TRUE(r.IsNotNull()); UT_TRUE(r.IsEmpty()); UT_EQ(false, s.Consume('a')); UT_EQ(false, s.Consume("word")); UT_EQ('\0', s.ConsumeFromEnd( )); UT_EQ(0, s.ConsumeFromEnd(0)); UT_EQ(0, s.ConsumeFromEnd(5)); UT_EQ(false, s.ConsumeFromEnd('a')); UT_EQ(false, s.ConsumeFromEnd("word")); } // substring of length 1 { Substring s = new Substring("aaaaaaaaaaaa"); Substring r = new Substring("oldval"); s.Start = s.End = 5; UT_EQ('a', s.Consume( )); UT_EQ(0, s.Length()); s.Start = s.End = 5; UT_EQ(1, s.Consume(0)); UT_EQ(1, s.Length()); s.Start = s.End = 5; UT_EQ(0, s.Consume(1, r)); UT_EQ(0, s.Length()); UT_TRUE(r.Equals("a")); s.Start = s.End = 5; UT_EQ(0, s.Consume(5, r)); UT_EQ(0, s.Length()); UT_TRUE(r.Equals("a")); s.Start = s.End = 5; UT_EQ(true, s.Consume('a')); UT_EQ(0, s.Length()); s.Start = s.End = 5; UT_EQ(false, s.Consume('b')); UT_EQ(1, s.Length()); s.Start = s.End = 5; UT_EQ(false, s.Consume("word")); UT_EQ(1, s.Length()); s.Start = s.End = 5; UT_EQ('a', s.ConsumeFromEnd( )); UT_EQ(0, s.Length()); s.Start = s.End = 5; UT_EQ(1, s.ConsumeFromEnd(0)); UT_EQ(1, s.Length()); s.Start = s.End = 5; UT_EQ(0, s.ConsumeFromEnd(1)); UT_EQ(0, s.Length()); s.Start = s.End = 5; UT_EQ(0, s.ConsumeFromEnd(5)); UT_EQ(0, s.Length()); s.Start = s.End = 5; UT_EQ(true, s.ConsumeFromEnd('a')); UT_EQ(0, s.Length()); s.Start = s.End = 5; UT_EQ(false, s.ConsumeFromEnd('b')); UT_EQ(1, s.Length()); s.Start = s.End = 5; UT_EQ(false, s.ConsumeFromEnd("word")); UT_EQ(1, s.Length()); } // substring of length 2 { Substring s = new Substring("12ab3456"); Substring r = new Substring("oldval"); s.Start = 2; s.End = 3; UT_EQ('a', s.Consume( )); UT_EQ(1, s.Length()); UT_EQ('b', s.Consume( )); UT_EQ(0, s.Length()); s.Start = 2; s.End = 3; UT_EQ('b', s.ConsumeFromEnd( )); UT_EQ(1, s.Length()); UT_EQ('a', s.ConsumeFromEnd( )); UT_EQ(0, s.Length()); s.Start = 2; s.End = 3; UT_EQ(2, s.Consume(0, r)); UT_EQ(2, s.Length()); UT_TRUE(r.IsNotNull()); UT_TRUE(r.IsEmpty()); s.Start = 2; s.End = 3; UT_EQ(1, s.Consume(1, r)); UT_EQ(1, s.Length()); UT_TRUE(r.Equals("a")); s.Start = 2; s.End = 3; UT_EQ(0, s.Consume(2, r)); UT_EQ(0, s.Length()); UT_TRUE(r.Equals("ab")); s.Start = 2; s.End = 3; UT_EQ(0, s.Consume(3, r)); UT_EQ(0, s.Length()); UT_TRUE(r.Equals("ab")); s.Start = 2; s.End = 3; UT_EQ(2, s.ConsumeFromEnd(0, r)); UT_EQ(2, s.Length()); UT_TRUE(r.IsNotNull()); UT_TRUE(r.IsEmpty()); s.Start = 2; s.End = 3; UT_EQ(1, s.ConsumeFromEnd(1, r)); UT_EQ(1, s.Length()); UT_TRUE(r.Equals("b")); s.Start = 2; s.End = 3; UT_EQ(0, s.ConsumeFromEnd(2, r)); UT_EQ(0, s.Length()); UT_TRUE(r.Equals("ab")); s.Start = 2; s.End = 3; UT_EQ(0, s.ConsumeFromEnd(3, r)); UT_EQ(0, s.Length()); UT_TRUE(r.Equals("ab")); s.Start = 2; s.End = 3; UT_EQ(false, s.Consume('b')); UT_EQ(2, s.Length()); UT_EQ(true, s.Consume('a')); UT_EQ(1, s.Length()); UT_EQ(true, s.Consume('b')); UT_EQ(0, s.Length()); UT_EQ(false, s.Consume('a')); UT_EQ(0, s.Length()); UT_EQ(false, s.Consume('b')); UT_EQ(0, s.Length()); s.Start = 2; s.End = 3; UT_EQ(false, s.ConsumeFromEnd('a')); UT_EQ(2, s.Length()); UT_EQ(true, s.ConsumeFromEnd('b')); UT_EQ(1, s.Length()); UT_EQ(true, s.ConsumeFromEnd('a')); UT_EQ(0, s.Length()); UT_EQ(false, s.ConsumeFromEnd('b')); UT_EQ(0, s.Length()); UT_EQ(false, s.ConsumeFromEnd('a')); UT_EQ(0, s.Length()); s.Start = 2; s.End = 3; UT_EQ(false, s.Consume("word")); UT_EQ(2, s.Length()); s.Start = 2; s.End = 3; UT_EQ(false, s.Consume("AB")); UT_EQ(2, s.Length()); s.Start = 2; s.End = 3; UT_EQ(true, s.Consume("ab")); UT_EQ(0, s.Length()); s.Start = 2; s.End = 3; UT_EQ(false, s.ConsumeFromEnd("word")); UT_EQ(2, s.Length()); s.Start = 2; s.End = 3; UT_EQ(false, s.ConsumeFromEnd("AB")); UT_EQ(2, s.Length()); s.Start = 2; s.End = 3; UT_EQ(true, s.ConsumeFromEnd("ab")); UT_EQ(0, s.Length()); } // 3 words { Substring s = new Substring("word1 word2 word3"); UT_EQ('w', s.Consume( )); UT_EQ('o', s.Consume( )); UT_EQ('r', s.Consume( )); UT_EQ('d', s.Consume( )); UT_EQ('1', s.Consume( )); UT_EQ(false, s.Consume('w')); UT_EQ(true, s.Consume('w', Whitespaces.Trim)); UT_EQ(true, s.Consume('o', Whitespaces.Trim)); UT_EQ(false, s.Consume('o', Whitespaces.Trim)); UT_EQ(true, s.Consume('r', Whitespaces.Trim)); UT_EQ(false, s.Consume("D2", Whitespaces.Trim)); UT_EQ(false, s.Consume("D2")); UT_EQ(true, s.Consume("d2")); UT_EQ(2, s.Consume(4)); UT_EQ("d3", s.ToString()); s = new Substring("word1 word2 word3"); UT_EQ('3', s.ConsumeFromEnd( )); UT_EQ('d', s.ConsumeFromEnd( )); UT_EQ('r', s.ConsumeFromEnd( )); UT_EQ('o', s.ConsumeFromEnd( )); UT_EQ('w', s.ConsumeFromEnd( )); UT_EQ(false, s.ConsumeFromEnd('2')); UT_EQ(true, s.ConsumeFromEnd('2', Whitespaces.Trim)); UT_EQ(true, s.ConsumeFromEnd('d', Whitespaces.Trim)); UT_EQ(false, s.ConsumeFromEnd('d', Whitespaces.Trim)); UT_EQ(true, s.ConsumeFromEnd('r', Whitespaces.Trim)); UT_EQ(false, s.ConsumeFromEnd("WO", Whitespaces.Trim)); UT_EQ(false, s.ConsumeFromEnd("WO")); UT_EQ(true, s.ConsumeFromEnd("wo")); UT_EQ(2, s.ConsumeFromEnd(4)); UT_EQ("wo", s.ToString()); } // consume AString, Substring { Substring s = new Substring("word1 word2 word3 word4"); Substring sConsume = new Substring("1234word12", 4, 4); AString aConsume = new AString("word"); UT_EQ(true, s.Consume(sConsume)); UT_EQ(false, s.Consume(sConsume)); UT_EQ('1', s.Consume( )); UT_EQ(false, s.Consume(sConsume)); UT_EQ(true, s.Consume(sConsume, Whitespaces.Trim)); UT_EQ('2', s.Consume( )); UT_EQ(' ', s.Consume( )); UT_EQ(true, s.Consume(aConsume)); UT_EQ(false, s.Consume(aConsume)); UT_EQ('3', s.Consume( )); UT_EQ(false, s.Consume(aConsume)); UT_EQ(true, s.Consume(aConsume, Whitespaces.Trim)); s.Set("1word 2word 3word 4word"); UT_EQ(true, s.ConsumeFromEnd(sConsume)); UT_EQ(false, s.ConsumeFromEnd(sConsume)); UT_EQ('4', s.ConsumeFromEnd( )); UT_EQ(false, s.ConsumeFromEnd(sConsume)); UT_EQ(true, s.ConsumeFromEnd(sConsume, Whitespaces.Trim)); UT_EQ('3', s.ConsumeFromEnd( )); UT_EQ(' ', s.ConsumeFromEnd( )); UT_EQ(true, s.ConsumeFromEnd(aConsume)); UT_EQ(false, s.ConsumeFromEnd(aConsume)); UT_EQ('2', s.ConsumeFromEnd( )); UT_EQ(false, s.ConsumeFromEnd(aConsume)); UT_EQ(true, s.ConsumeFromEnd(aConsume, Whitespaces.Trim)); } }
/** ******************************************************************************************** * * The implementation of the abstract method of parent class TextLogger. Logs messages to the * application console and/or the VStudio output window. * * @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 msg The log message. * @param scope Information about the scope of the <em>Log Statement</em>.. * @param lineNumber The line number of a multi-line message, starting with 0. For * single line messages this is -1. **********************************************************************************************/ override protected void logText(Domain domain, Verbosity verbosity, AString msg, ScopeInfo scope, int lineNumber) { // get actual console attributes ConsoleColor actualFGCol = Console.ForegroundColor; ConsoleColor actualBGCol = Console.BackgroundColor; // loop over message, print the parts between the escape sequences Tokenizer msgParts = new Tokenizer(msg, '\x1B'); Substring actual = msgParts.Actual; Substring rest = msgParts.Rest; int column = 0; for (;;) { if (msgParts.Next(Whitespaces.Keep).IsNotEmpty()) { #if !(ALOX_WP71 || ALOX_WP8) Console.Write(msg.Buffer(), actual.Start, actual.Length()); #else Console.Write(msg.ToString(0, actual.Start, actual.Length()); #endif column += actual.Length(); } // end of loop? if (!msgParts.HasNext()) { break; } // found an ESC sequence char c = rest.Consume(); // Colors bool isForeGround = true; if (c == 'C' || c == 'c') { isForeGround = c == 'c'; c = rest.Consume(); int colNo = c - '0'; ALIB.ASSERT_WARNING(colNo >= 0 && colNo <= 9, "Unknown ESC-c code"); // set color if (colNo >= 0 && colNo <= 8 || colNo == 8) { ConsoleColor[] cols = (isForeGround ? !IsBackgroundLight : IsBackgroundLight) ? lightColors : darkColors; if (isForeGround) { Console.ForegroundColor = cols[colNo]; } else { Console.BackgroundColor = cols[colNo]; } } else if (colNo == 9) { if (isForeGround) { Console.ForegroundColor = actualFGCol; } else { Console.BackgroundColor = actualBGCol; } } else { ALIB.WARNING("Unknown ESC- code"); } } // Styles else if (c == 's') { // bold/italics style not supported in Windows console // reset all if (rest.Consume() == 'a') { Console.ForegroundColor = actualFGCol; Console.BackgroundColor = actualBGCol; } } // auto tab / end of meta else if (c == 't' || c == 'A') { bool endOfMeta = c == 'A'; c = rest.Consume(); int extraSpace = c >= '0' && c <= '9' ? (int) (c - '0') : (int)(c - 'A') + 10; int tabStop = AutoSizes.Next(column, extraSpace); Util.WriteSpaces(Console.Out, tabStop - column); column = tabStop; if (endOfMeta) { switch (verbosity) { case Verbosity.Verbose: Console.ForegroundColor = MsgColorVerbose; break; case Verbosity.Info: Console.ForegroundColor = MsgColorInfo; break; case Verbosity.Warning: Console.ForegroundColor = MsgColorWarning; break; case Verbosity.Error: Console.ForegroundColor = MsgColorError; break; default: break; } } } // Link (we just colorize links here) else if (c == 'l') { if (rest.Consume() == 'S') { Console.ForegroundColor = IsBackgroundLight ? ConsoleColor.DarkBlue : ConsoleColor.Blue; } else { Console.ForegroundColor = actualFGCol; } } else { ALIB.WARNING("Unknown ESC code"); } } // write loop // reset colors Console.ForegroundColor = actualFGCol; Console.BackgroundColor = actualBGCol; // write NL #if !(ALOX_WP71 || ALOX_WP8) Console.WriteLine(); #else Console.WriteLine(); #endif }
// ############################################################################################# // file IO // ############################################################################################# /** **************************************************************************************** * Clears all configuration data and reads the file. It might happen that lines are * ignored or otherwise marked as faulty. All numbers of such lines get collected in * field LinesWithReadErrors. * @return Returns the #Status of the operation. ******************************************************************************************/ public IniFile.Status ReadFile() { Clear(); LastStatus = Status.OK; // read all variables StreamReader file; try { file = new StreamReader(FileName.ToString()); } catch (Exception) { return(LastStatus = Status.ERROR_OPENING_FILE); } String lineS; AString name = new AString(); AString value = new AString(); AString comments = new AString(); Section actSection = Sections[0]; Substring line = new Substring(); Tokenizer tn = new Tokenizer(); int lineNo = 0; bool fileHeaderRead = false; LinesWithReadErrors.Clear(); while ((lineS = file.ReadLine()) != null) { lineNo = 0; // place in AString line.Set(lineS).Trim(); // empty line? if (line.IsEmpty()) { // already collecting a comment? if (comments.IsNotEmpty()) { // first empty line in file found? if (!fileHeaderRead) { //store comments belonging to file fileHeaderRead = true; FileComments = comments; comments = new AString(); continue; } comments.NewLine(); } continue; } // comments line: find comment character '#', ';' or // if (startsWithCommentSymbol(line)) { //gather in comments string if (comments.IsNotEmpty()) { comments.NewLine(); } line.CopyTo(comments, true); continue; } // section line if (line.Consume('[')) { fileHeaderRead = true; // we do not care if there is no closing bracket. But if there is one, we remove it. if (!line.ConsumeFromEnd(']')) { LinesWithReadErrors.Add(lineNo); } // search the section in our section list (if section existed already, new comments // are dropped) actSection = SearchOrCreateSection(line, comments); comments.Clear(); continue; } // variable line? If not, we just drop the line! tn.Set(line, '='); tn.Next(); if (!tn.HasNext()) { LinesWithReadErrors.Add(lineNo); continue; } tn.Actual.CopyTo(name); if (tn.GetRest().IsEmpty()) { LinesWithReadErrors.Add(lineNo); continue; } value.Clear(); Substring valueRead = tn.Actual; // read continues as long as lines end with '\' (must not be '\\') char delim = '\0'; while (valueRead.CharAtEnd() == '\\' && valueRead.CharAtEnd(1) != '\\') { // search end before '\'. The first of all broken lines determines the delimiter valueRead.End--; valueRead.TrimEnd(); if (delim == 0) { delim = valueRead.CharAtEnd(); if (delim == '\"' || char.IsLetterOrDigit(delim)) { delim = '\0'; } } removeEscapeSequences(valueRead, value); if ((lineS = file.ReadLine()) == null) { // last line of the file ended with '\' ! valueRead.Clear(); break; } valueRead.Set(lineS).Trim(); } removeEscapeSequences(valueRead, value); actSection.Insert(name, value, comments).Delim = delim; comments.Clear(); } file.Close(); return(LastStatus); }
// ############################################################################################# // Protected interface // ############################################################################################# /** **************************************************************************************** * Gets a node. If not existent and parameter \p create is \c true, the node is created. * @param key The key to the stored value. * @param create Flag if a non-existent entry should be created. * @param separators A list of characters recognized as separators. * @return Returns the ourselves or a child node representing the key string. ******************************************************************************************/ protected PathMap <StoreT> get(Substring key, bool create, AString separators) { int idx = 0; int pLen = Path.Length(); if (pLen > 0) { int cmpLen = pLen < key.Length() ? pLen : key.Length(); char[] kBuf = key.Buf; char[] pBuf = Path.Buffer(); while (idx < cmpLen && kBuf[key.Start + idx] == pBuf[idx]) { idx++; } key.Consume(idx); } // all of 'our' path characters matched if (idx == pLen) { // identical to the searched string? if (key.IsEmpty()) { return(this); } // return matching child foreach (PathMap <StoreT> child in Childs) { if (key.CharAtStart() == child.Path.CharAtStart()) { PathMap <StoreT> search = child.get(key, create, separators); if (search != null) { return(search); } } } // no child found if (create) { PathMap <StoreT> newChild = null; newChild = new PathMap <StoreT>(this); newChild.Path._(key); Childs.Add(newChild); return(newChild); } } // nothing matched else if (idx == 0) { return(null); } // just a part of us matched else if (create) { // create new child receiving our old path (rest), our value and childs PathMap <StoreT> child1 = new PathMap <StoreT>(this); child1.Path._(Path, idx); List <PathMap <StoreT> > tempList = child1.Childs; foreach (PathMap <StoreT> child in Childs) { child.Parent = child1; } child1.Childs = Childs; Childs = tempList; child1.Value = Value; Childs.Clear(); Childs.Add(child1); // cut my path and clear my value Path.SetLength_NC(idx); Value = default(StoreT); // create second child if remaining path is not empty if (key.IsNotEmpty()) { PathMap <StoreT> child2 = new PathMap <StoreT>(this); child2.Path._(key); Childs.Add(child2); return(child2); } return(this); } // return us, or if this is not a real node, our parent if (Parent == null || idx == 0 || separators.IndexOf(Path.CharAt_NC(idx - 1)) >= 0) { return(this); } else { return(Parent); } }