/** ******************************************************************************************** * 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)); }
// ############################################################################################# // 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); }
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)); } }
// ############################################################################################# // 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); } }