Example #1
0
        /// ------------------------------------------------------------------------------------
        /// <summary>
        /// Checks for missing chapters in the current book.
        /// </summary>
        /// ------------------------------------------------------------------------------------
        private void CheckForMissingChapters(bool[] chaptersFound)
        {
            for (int chap = 1; chap < chaptersFound.Length; chap++)
            {
                if (chaptersFound[chap] || (m_nChapterToCheck != 0 && chap != m_nChapterToCheck))
                {
                    continue;
                }

                // Find the first chapter token that immediately precedes where the
                // missing chapter would have a token if it weren't missing.
                ChapterToken precedingChapter = null;
                foreach (ChapterToken chapToken in m_chapTokens)
                {
                    if (chapToken.ChapterNumber > chap)
                    {
                        break;
                    }
                    precedingChapter = chapToken;
                }

                // TODO: Deal with what token to use if a book has no chapters at all.
                // This should always succeed
                int        offset = 0;
                ITextToken token  = null;
                if (precedingChapter != null)
                {
                    token  = precedingChapter.Token;
                    offset = precedingChapter.Implicit ? 0 : token.Text.Length;
                }
                else if (m_chapTokens.Count > 0)
                {
                    token = m_chapTokens[0].Token;
                }

                if (token != null)
                {
                    BCVRef scrRefStart = new BCVRef(BCVRef.BookToNumber(token.ScrRefString), chap, 0);
                    token.MissingStartRef = scrRefStart;
                    token.MissingEndRef   = null;
                    AddError(token, offset, 0, Localize("Missing chapter number {0}"), chap);
                }
            }
        }
Example #2
0
        /// ------------------------------------------------------------------------------------
        /// <summary>
        /// Check verse numbers.
        /// </summary>
        /// ------------------------------------------------------------------------------------
        private void CheckVerseNumbers(ChapterToken chapToken, int bookId)
        {
            int  lastVrsInChap     = m_versification.LastVerse(bookId, chapToken.ChapterNumber);
            int  nextExpectedVerse = 1;
            bool expectingPartB    = false;
            int  prevVerseStart    = 0;
            int  prevVerseEnd      = 0;

            ITextToken[] versesFound = new ITextToken[lastVrsInChap + 1];
            versesFound[0] = chapToken.Token;

            foreach (VerseToken verseToken in chapToken.VerseTokens)
            {
                ITextToken token            = verseToken.VerseNumber;
                ITextToken reportedToken    = token;
                string     msg              = null;
                int        offset           = 0;
                int        length           = token.Text.Length;
                object[]   errorArgs        = null;
                bool       countFoundVerses = false;
                int        curVerseStart;
                int        curVerseEnd;
                VersePart  vrsPart;

                if (verseToken.ImplicitVerseNumber == 1)
                {
                    versesFound[1] = token;
                    continue;
                }

                ParseVerseResult parseResult = ParseVerseNumber(token.Text,
                                                                out curVerseStart, out curVerseEnd, out vrsPart);

                if (parseResult == ParseVerseResult.ValidWithSpaceInVerse)
                {
                    // Log error telling user there are spaces before or after the verse
                    // number. This means the space(s) have the verse number style. This isn't
                    // considered an invalid verse number, but we do need to tell the user.
                    AddError(token, 0, token.Text.Length,
                             Localize("Space found in verse number"), token.Text);
                }
                else if (parseResult == ParseVerseResult.ValidWithSpaceInVerseBridge)
                {
                    // Log error telling user there are spaces in a verse bridge. This
                    // means the space(s) have the verse number style. This isn't considered
                    // an invalid verse number, but we do need to tell the user.
                    AddError(token, 0, token.Text.Length,
                             Localize("Space found in verse bridge"), token.Text);
                }

                if (parseResult == ParseVerseResult.Invalid)
                {
                    msg = Localize("Invalid verse number");
                }
                else if ((parseResult != ParseVerseResult.InvalidFormat) && VersesAlreadyFound(curVerseStart, curVerseEnd, versesFound) &&
                         !(expectingPartB && vrsPart == VersePart.PartB))
                {
                    if (AnyOverlappingVerses(curVerseStart, curVerseEnd,
                                             prevVerseStart, prevVerseEnd, out errorArgs))
                    {
                        // Duplicate verse(s) found.
                        msg = (errorArgs.Length == 1 ?
                               Localize("Duplicate verse number") :
                               Localize("Duplicate verse numbers"));
                    }
                    else
                    {
                        // Verse number(s) are unexpected
                        msg = (curVerseStart == curVerseEnd ?
                               Localize("Unexpected verse number") :
                               Localize("Unexpected verse numbers"));
                    }
                }
                else if (AnyOverlappingVerses(curVerseStart, curVerseEnd,
                                              lastVrsInChap + 1, int.MaxValue, out errorArgs))
                {
                    countFoundVerses = true;
                    // Start and/or end verse is out of range
                    msg = (errorArgs.Length == 1 ?
                           Localize("Verse number out of range") :
                           Localize("Verse numbers out of range"));
                }
                else if (curVerseStart < nextExpectedVerse)
                {
                    // Verse number(s) are out of order
                    countFoundVerses = true;
                    if (nextExpectedVerse <= lastVrsInChap)
                    {
                        errorArgs = new object[] { nextExpectedVerse };
                        msg       = (curVerseStart == curVerseEnd ?
                                     Localize("Verse number out of order; expected verse {0}") :
                                     Localize("Verse numbers out of order; expected verse {0}"));
                    }
                    else
                    {
                        msg = (curVerseStart == curVerseEnd ?
                               Localize("Verse number out of order") :
                               Localize("Verse numbers out of order"));
                    }
                }
                else if (((vrsPart == VersePart.PartB) != expectingPartB) &&
                         (curVerseStart == curVerseEnd))
                {
                    // Missing part A or B
                    // TODO: cover cases like "4a 5-7" and "4 5b-7". This would require
                    // ParseVerseNumber() to detect verse parts at the beginning of bridges.
                    reportedToken = (vrsPart == VersePart.PartB ? token : versesFound[prevVerseEnd]);
                    msg           = Localize("Missing verse number {0}");
                    offset        = (vrsPart == VersePart.PartB ? 0 : reportedToken.Text.Length);
                    length        = 0;
                    int    reportedVrsNum = (vrsPart == VersePart.PartB ? curVerseStart : prevVerseEnd);
                    string fmt            = (vrsPart == VersePart.PartB ? "{0}a" : "{0}b");
                    errorArgs        = new object[] { string.Format(fmt, reportedVrsNum) };
                    countFoundVerses = true;
                }
                else if ((vrsPart == VersePart.PartB && curVerseStart > prevVerseEnd) &&
                         (curVerseStart == curVerseEnd))
                {
                    // Missing both a part B and A
                    reportedToken = versesFound[prevVerseEnd];

                    AddError(reportedToken, reportedToken.Text.Length, 0,
                             Localize("Missing verse number {0}"),
                             new object[] { string.Format("{0}b", prevVerseEnd) });

                    AddError(token, 0, 0, Localize("Missing verse number {0}"),
                             new object[] { string.Format("{0}a", curVerseStart) });
                }

                if (msg != null)
                {
                    // Report the error found.
                    if (errorArgs == null)
                    {
                        AddError(reportedToken, offset, length, msg);
                    }
                    else
                    {
                        AddError(reportedToken, offset, length, msg, errorArgs);
                    }
                }

                if (msg == null || countFoundVerses)
                {
                    // No error was found for the current verse range so set all the verses
                    // in our found verse list corresponding to those in the range.
                    for (int i = curVerseStart; i <= Math.Min(curVerseEnd, lastVrsInChap); i++)
                    {
                        versesFound[i] = token;
                    }
                }

                if (parseResult == ParseVerseResult.InvalidFormat)
                {
                    AddError(token, 0, token.Text.Length, Localize("Invalid verse number"), token.Text);
                }

                // only worry about this if the chapter and/or verse tokens are in order
                if (verseToken.VerseTextCount < 1)
                {
                    AddError(verseToken.VerseNumber, 0, verseToken.VerseNumber.Text.Length,
                             Localize("Missing verse text in verse {0}"), verseToken.VerseNumber.Text);
                }

                // Determine next expected verse.
                // Don't expect a partB if there was an error with partA
                expectingPartB = (vrsPart == VersePart.PartA && msg == null);
                if (!expectingPartB && curVerseEnd <= lastVrsInChap)
                {
                    nextExpectedVerse = curVerseEnd + 1;
                }

                prevVerseStart = curVerseStart;
                prevVerseEnd   = curVerseEnd;
            }

            CheckForMissingVerses(versesFound, bookId, chapToken.ChapterNumber);
        }
Example #3
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Check verse numbers.
		/// </summary>
		/// ------------------------------------------------------------------------------------
		private void CheckVerseNumbers(ChapterToken chapToken, int bookId)
		{
			int lastVrsInChap = m_versification.LastVerse(bookId, chapToken.ChapterNumber);
			int nextExpectedVerse = 1;
			bool expectingPartB = false;
			int prevVerseStart = 0;
			int prevVerseEnd = 0;
			ITextToken[] versesFound = new ITextToken[lastVrsInChap + 1];
			versesFound[0] = chapToken.Token;

			foreach (VerseToken verseToken in chapToken.VerseTokens)
			{
				ITextToken token = verseToken.VerseNumber;
				ITextToken reportedToken = token;
				string msg = null;
				int offset = 0;
				int length = token.Text.Length;
				object[] errorArgs = null;
				bool countFoundVerses = false;
				int curVerseStart;
				int curVerseEnd;
				VersePart vrsPart;

				if (verseToken.ImplicitVerseNumber == 1)
				{
					versesFound[1] = token;
					continue;
				}

				ParseVerseResult parseResult = ParseVerseNumber(token.Text,
					out curVerseStart, out curVerseEnd, out vrsPart);

				if (parseResult == ParseVerseResult.ValidWithSpaceInVerse)
				{
					// Log error telling user there are spaces before or after the verse
					// number. This means the space(s) have the verse number style. This isn't
					// considered an invalid verse number, but we do need to tell the user.
					AddError(token, 0, token.Text.Length,
						Localize("Space found in verse number"), token.Text);
				}
				else if (parseResult == ParseVerseResult.ValidWithSpaceInVerseBridge)
				{
					// Log error telling user there are spaces in a verse bridge. This
					// means the space(s) have the verse number style. This isn't considered
					// an invalid verse number, but we do need to tell the user.
					AddError(token, 0, token.Text.Length,
						Localize("Space found in verse bridge"), token.Text);
				}

				if (parseResult == ParseVerseResult.Invalid)
				{
					msg = Localize("Invalid verse number");
				}
				else if ((parseResult != ParseVerseResult.InvalidFormat) && VersesAlreadyFound(curVerseStart, curVerseEnd, versesFound) &&
					!(expectingPartB && vrsPart == VersePart.PartB))
				{
					if (AnyOverlappingVerses(curVerseStart, curVerseEnd,
						prevVerseStart, prevVerseEnd, out errorArgs))
					{
						// Duplicate verse(s) found.
						msg = (errorArgs.Length == 1 ?
							Localize("Duplicate verse number") :
							Localize("Duplicate verse numbers"));
					}
					else
					{
						// Verse number(s) are unexpected
						msg = (curVerseStart == curVerseEnd ?
							Localize("Unexpected verse number") :
							Localize("Unexpected verse numbers"));
					}
				}
				else if (AnyOverlappingVerses(curVerseStart, curVerseEnd,
					lastVrsInChap + 1, int.MaxValue, out errorArgs))
				{
					countFoundVerses = true;
					// Start and/or end verse is out of range
					msg = (errorArgs.Length == 1 ?
						Localize("Verse number out of range") :
						Localize("Verse numbers out of range"));
				}
				else if (curVerseStart < nextExpectedVerse)
				{
					// Verse number(s) are out of order
					countFoundVerses = true;
					if (nextExpectedVerse <= lastVrsInChap)
					{
						errorArgs = new object[] { nextExpectedVerse };
						msg = (curVerseStart == curVerseEnd ?
							Localize("Verse number out of order; expected verse {0}") :
							Localize("Verse numbers out of order; expected verse {0}"));
					}
					else
					{
						msg = (curVerseStart == curVerseEnd ?
							Localize("Verse number out of order") :
							Localize("Verse numbers out of order"));
					}
				}
				else if (((vrsPart == VersePart.PartB) != expectingPartB) &&
					(curVerseStart == curVerseEnd))
				{
					// Missing part A or B
					// TODO: cover cases like "4a 5-7" and "4 5b-7". This would require
					// ParseVerseNumber() to detect verse parts at the beginning of bridges.
					reportedToken = (vrsPart == VersePart.PartB ? token : versesFound[prevVerseEnd]);
					msg = Localize("Missing verse number {0}");
					offset = (vrsPart == VersePart.PartB ? 0 : reportedToken.Text.Length);
					length = 0;
					int reportedVrsNum = (vrsPart == VersePart.PartB ? curVerseStart : prevVerseEnd);
					string fmt = (vrsPart == VersePart.PartB ? "{0}a" : "{0}b");
					errorArgs = new object[] { string.Format(fmt, reportedVrsNum) };
					countFoundVerses = true;
				}
				else if ((vrsPart == VersePart.PartB && curVerseStart > prevVerseEnd) &&
					(curVerseStart == curVerseEnd))
				{
					// Missing both a part B and A
					reportedToken = versesFound[prevVerseEnd];

					AddError(reportedToken, reportedToken.Text.Length, 0,
						Localize("Missing verse number {0}"),
						new object[] { string.Format("{0}b", prevVerseEnd) });

					AddError(token, 0, 0, Localize("Missing verse number {0}"),
						new object[] { string.Format("{0}a", curVerseStart) });
				}

				if (msg != null)
				{
					// Report the error found.
					if (errorArgs == null)
						AddError(reportedToken, offset, length, msg);
					else
						AddError(reportedToken, offset, length, msg, errorArgs);
				}

				if (msg == null || countFoundVerses)
				{
					// No error was found for the current verse range so set all the verses
					// in our found verse list corresponding to those in the range.
					for (int i = curVerseStart; i <= Math.Min(curVerseEnd, lastVrsInChap); i++)
						versesFound[i] = token;
				}

				if (parseResult == ParseVerseResult.InvalidFormat)
					AddError(token, 0, token.Text.Length, Localize("Invalid verse number"), token.Text);

				// only worry about this if the chapter and/or verse tokens are in order
				if (verseToken.VerseTextCount < 1)
				{
					AddError(verseToken.VerseNumber, 0, verseToken.VerseNumber.Text.Length,
						Localize("Missing verse text in verse {0}"), verseToken.VerseNumber.Text);
				}

				// Determine next expected verse.
				// Don't expect a partB if there was an error with partA
				expectingPartB = (vrsPart == VersePart.PartA && msg == null);
				if (!expectingPartB && curVerseEnd <= lastVrsInChap)
					nextExpectedVerse = curVerseEnd + 1;

				prevVerseStart = curVerseStart;
				prevVerseEnd = curVerseEnd;
			}

			CheckForMissingVerses(versesFound, bookId, chapToken.ChapterNumber);
		}
Example #4
0
        /// ------------------------------------------------------------------------------------
        /// <summary>
        /// Checks the given tokens for chapter/verse errors and calls the given RecordError
        /// handler for each one.
        /// </summary>
        /// <param name="toks">The tokens to check.</param>
        /// <param name="record">Method to call to record errors.</param>
        /// ------------------------------------------------------------------------------------
        public void Check(IEnumerable <ITextToken> toks, RecordErrorHandler record)
        {
            GetParameters();

            m_recordError = record;
            m_versesFound = new List <int>();
            m_chapTokens.Clear();

            ChapterToken currChapterToken = null;
            VerseToken   currVerseToken   = null;

            foreach (ITextToken token in toks)
            {
                // This token is only necessary when a chapter one is missing
                // and we need a token to use for reporting that it's missing.
                if (m_fallbackToken == null)
                {
                    m_fallbackToken = token;
                }

                if (token.TextType == TextType.ChapterNumber)
                {
                    currChapterToken = new ChapterToken(token, m_chapterNumberFormat);
                    currVerseToken   = null;
                    m_chapTokens.Add(currChapterToken);
                }
                else if (token.TextType == TextType.VerseNumber)
                {
                    if (currChapterToken == null)
                    {
                        //assume chapter one
                        currChapterToken = new ChapterToken(token, 1);
                        m_chapTokens.Add(currChapterToken);
                    }

                    currVerseToken = new VerseToken(token);
                    currChapterToken.VerseTokens.Add(currVerseToken);
                }
                else if (token.TextType == TextType.Verse)
                {
                    if (currChapterToken == null)
                    {
                        // no chapter token and no verse number token
                        // oh no! use verse text token as default, but system
                        // should error on missing verse first.
                        if (currVerseToken == null)
                        {
                            //assume chapter one
                            currChapterToken = new ChapterToken(token, 1);
                            m_chapTokens.Add(currChapterToken);

                            //assume verse one
                            currVerseToken = new VerseToken(token, 1);
                            currChapterToken.VerseTokens.Add(currVerseToken);
                        }
                        // no chapter token, but we have verse number token
                        // then use the verse number token
                        else
                        {
                            // this case should not happen because chapter tokens
                            // are automatically created if a verse number token is
                            // encountered first
                            Debug.Assert(false, "verse number token found without chapter number token");
                        }
                    }
                    else
                    {
                        // we have a chapter token, but no verse number token
                        // use the chapter token as the default token.
                        if (currVerseToken == null)
                        {
                            //assume verse one
                            currVerseToken = new VerseToken(token, 1);
                            currChapterToken.VerseTokens.Add(currVerseToken);
                        }
                        // we have a chapter token, and a verse number token
                        // we are happy
                        else
                        {
                            // do nothing
                        }
                    }
                    currVerseToken.IncrementVerseTextCount(token);
                }
            }

            CheckChapterNumbers();
        }
Example #5
0
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Checks the given tokens for chapter/verse errors and calls the given RecordError
		/// handler for each one.
		/// </summary>
		/// <param name="toks">The tokens to check.</param>
		/// <param name="record">Method to call to record errors.</param>
		/// ------------------------------------------------------------------------------------
		public void Check(IEnumerable<ITextToken> toks, RecordErrorHandler record)
		{
			GetParameters();

			m_recordError = record;
//			m_versesFound = new List<int>();
			m_chapTokens.Clear();

			ChapterToken currChapterToken = null;
			VerseToken currVerseToken = null;

			foreach (ITextToken token in toks)
			{
				// This token is only necessary when a chapter one is missing
				// and we need a token to use for reporting that it's missing.
				if (m_fallbackToken == null)
					m_fallbackToken = token;

				if (token.TextType == TextType.ChapterNumber)
				{
					currChapterToken = new ChapterToken(token, m_chapterNumberFormat);
					currVerseToken = null;
					m_chapTokens.Add(currChapterToken);
				}
				else if (token.TextType == TextType.VerseNumber)
				{
					if (currChapterToken == null)
					{
						//assume chapter one
						currChapterToken = new ChapterToken(token, 1);
						m_chapTokens.Add(currChapterToken);
					}

					currVerseToken = new VerseToken(token);
					currChapterToken.VerseTokens.Add(currVerseToken);
				}
				else if (token.TextType == TextType.Verse)
				{
					if (currChapterToken == null)
					{
						// no chapter token and no verse number token
						// oh no! use verse text token as default, but system
						// should error on missing verse first.
						if (currVerseToken == null)
						{
							//assume chapter one
							currChapterToken = new ChapterToken( token, 1);
							m_chapTokens.Add(currChapterToken);

							//assume verse one
							currVerseToken = new VerseToken(token, 1);
							currChapterToken.VerseTokens.Add(currVerseToken);
						}
						// no chapter token, but we have verse number token
						// then use the verse number token
						else
						{
							// this case should not happen because chapter tokens
							// are automatically created if a verse number token is
							// encountered first
							Debug.Assert(false, "verse number token found without chapter number token");
						}
					}
					else
					{
						// we have a chapter token, but no verse number token
						// use the chapter token as the default token.
						if (currVerseToken == null)
						{
							//assume verse one
							currVerseToken = new VerseToken(token, 1);
							currChapterToken.VerseTokens.Add(currVerseToken);
						}
						// we have a chapter token, and a verse number token
						// we are happy
						else
						{
							// do nothing
						}
					}
					currVerseToken.IncrementVerseTextCount(token);
				}
			}

			CheckChapterNumbers();
		}