You are viewing a plain text version of this content. The canonical link for it is here.
Posted to doxia-commits@maven.apache.org by vs...@apache.org on 2008/03/12 12:26:39 UTC
svn commit: r636283 -
/maven/doxia/doxia/trunk/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptParser.java
Author: vsiveton
Date: Wed Mar 12 04:26:31 2008
New Revision: 636283
URL: http://svn.apache.org/viewvc?rev=636283&view=rev
Log:
o increased visibility of some methods/fields
o improved the readingness
Modified:
maven/doxia/doxia/trunk/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptParser.java
Modified: maven/doxia/doxia/trunk/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptParser.java
URL: http://svn.apache.org/viewvc/maven/doxia/doxia/trunk/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptParser.java?rev=636283&r1=636282&r2=636283&view=diff
==============================================================================
--- maven/doxia/doxia/trunk/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptParser.java (original)
+++ maven/doxia/doxia/trunk/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptParser.java Wed Mar 12 04:26:31 2008
@@ -125,7 +125,7 @@
"COMMENT_BLOCK" };
/** An array of spaces. */
- private static final char SPACES[] = {
+ protected static final char SPACES[] = {
' ',
' ',
' ',
@@ -219,18 +219,9 @@
// Instance fields
// ----------------------------------------------------------------------
- /** sourceContent. */
- private String sourceContent;
-
/** the AptSource. */
private AptSource source;
- /** the sink to receive the events. */
- private Sink sink;
-
- /** a line of AptSource. */
- private String line;
-
/** a block of AptSource. */
private Block block;
@@ -240,6 +231,15 @@
/** blockLineNumber. */
private int blockLineNumber;
+ /** sourceContent. */
+ protected String sourceContent;
+
+ /** the sink to receive the events. */
+ protected Sink sink;
+
+ /** a line of AptSource. */
+ protected String line;
+
// ----------------------------------------------------------------------
// Public methods
// ----------------------------------------------------------------------
@@ -313,208 +313,611 @@
}
// ----------------------------------------------------------------------
- // Private methods
+ // Protected methods
// ----------------------------------------------------------------------
/**
- * Parse the head of the Apt source document.
+ * Parse the next line of the Apt source document.
*
* @throws AptParseException if something goes wrong.
*/
- private void traverseHead()
+ protected void nextLine()
throws AptParseException
{
- sink.head();
-
- if ( block != null && block.getType() == TITLE )
- {
- block.traverse();
- nextBlock();
- }
-
- sink.head_();
+ line = source.getNextLine();
}
/**
- * Parse the body of the Apt source document.
+ * Parse the given text.
*
+ * @param text the text to parse.
+ * @param begin offset.
+ * @param end offset.
+ * @param sink the sink to receive the events.
* @throws AptParseException if something goes wrong.
*/
- private void traverseBody()
+ protected void doTraverseText( String text, int begin, int end, Sink sink )
throws AptParseException
{
- sink.body();
-
- if ( block != null )
- {
- traverseSectionBlocks();
- }
+ boolean anchor = false;
+ boolean link = false;
+ boolean italic = false;
+ boolean bold = false;
+ boolean monospaced = false;
+ StringBuffer buffer = new StringBuffer( end - begin );
- while ( block != null )
+ for ( int i = begin; i < end; ++i )
{
- traverseSection( 0 );
- }
+ char c = text.charAt( i );
+ switch ( c )
+ {
+ case BACKSLASH:
+ if ( i + 1 < end )
+ {
+ char escaped = text.charAt( i + 1 );
+ switch ( escaped )
+ {
+ case SPACE:
+ ++i;
+ flushTraversed( buffer, sink );
+ sink.nonBreakingSpace();
+ break;
+ case '\r':
+ case '\n':
+ ++i;
+ // Skip white space which may follow a line break.
+ while ( i + 1 < end && Character.isWhitespace( text.charAt( i + 1 ) ) )
+ {
+ ++i;
+ }
+ flushTraversed( buffer, sink );
+ sink.lineBreak();
+ break;
+ case BACKSLASH:
+ case PIPE:
+ case COMMENT:
+ case EQUAL:
+ case MINUS:
+ case PLUS:
+ case STAR:
+ case LEFT_SQUARE_BRACKET:
+ case RIGHT_SQUARE_BRACKET:
+ case LESS_THAN:
+ case GREATER_THAN:
+ case LEFT_CURLY_BRACKET:
+ case RIGHT_CURLY_BRACKET:
+ ++i;
+ buffer.append( escaped );
+ break;
+ case 'x':
+ if ( i + 3 < end && isHexChar( text.charAt( i + 2 ) )
+ && isHexChar( text.charAt( i + 3 ) ) )
+ {
+ int value = '?';
+ try
+ {
+ value = Integer.parseInt( text.substring( i + 2, i + 4 ), 16 );
+ }
+ catch ( NumberFormatException e )
+ {
+ if ( getLog().isDebugEnabled() )
+ {
+ getLog().debug( "Not a number: " + text.substring( i + 2, i + 4 ) );
+ }
+ }
- sink.body_();
- }
+ i += 3;
+ buffer.append( (char) value );
+ }
+ else
+ {
+ buffer.append( BACKSLASH );
+ }
+ break;
+ case 'u':
+ if ( i + 5 < end && isHexChar( text.charAt( i + 2 ) )
+ && isHexChar( text.charAt( i + 3 ) ) && isHexChar( text.charAt( i + 4 ) )
+ && isHexChar( text.charAt( i + 5 ) ) )
+ {
+ int value = '?';
+ try
+ {
+ value = Integer.parseInt( text.substring( i + 2, i + 6 ), 16 );
+ }
+ catch ( NumberFormatException e )
+ {
+ if ( getLog().isDebugEnabled() )
+ {
+ getLog().debug( "Not a number: " + text.substring( i + 2, i + 6 ) );
+ }
+ }
- /**
- * Parse a section of the Apt source document.
- *
- * @param level The section level.
- * @throws AptParseException if something goes wrong.
- */
- private void traverseSection( int level )
- throws AptParseException
- {
- if ( block == null )
- {
- return;
- }
+ i += 5;
+ buffer.append( (char) value );
+ }
+ else
+ {
+ buffer.append( BACKSLASH );
+ }
+ break;
+ default:
+ if ( isOctalChar( escaped ) )
+ {
+ int octalChars = 1;
+ if ( isOctalChar( charAt( text, end, i + 2 ) ) )
+ {
+ ++octalChars;
+ if ( isOctalChar( charAt( text, end, i + 3 ) ) )
+ {
+ ++octalChars;
+ }
+ }
+ int value = '?';
+ try
+ {
+ value = Integer.parseInt( text.substring( i + 1, i + 1 + octalChars ), 8 );
+ }
+ catch ( NumberFormatException e )
+ {
+ if ( getLog().isDebugEnabled() )
+ {
+ getLog().debug(
+ "Not a number: "
+ + text.substring( i + 1, i + 1 + octalChars ) );
+ }
+ }
- int type = SECTION1 + level;
+ i += octalChars;
+ buffer.append( (char) value );
+ }
+ else
+ {
+ buffer.append( BACKSLASH );
+ }
+ }
+ }
+ else
+ {
+ buffer.append( BACKSLASH );
+ }
+ break;
- expectedBlock( type );
+ case LEFT_CURLY_BRACKET: /*}*/
+ if ( !anchor && !link )
+ {
+ if ( i + 1 < end && text.charAt( i + 1 ) == LEFT_CURLY_BRACKET /*}*/)
+ {
+ ++i;
+ link = true;
+ flushTraversed( buffer, sink );
- switch ( level )
- {
- case 0:
- sink.section1();
- break;
- case 1:
- sink.section2();
- break;
- case 2:
- sink.section3();
- break;
- case 3:
- sink.section4();
- break;
- case 4:
- sink.section5();
- break;
- default:
- break;
- }
+ String linkAnchor = null;
- block.traverse();
+ if ( i + 1 < end && text.charAt( i + 1 ) == LEFT_CURLY_BRACKET /*}*/)
+ {
+ ++i;
+ StringBuffer buf = new StringBuffer();
+ i = skipTraversedLinkAnchor( text, i + 1, end, buf );
+ linkAnchor = buf.toString();
+ }
- nextBlock();
+ if ( linkAnchor == null )
+ {
+ linkAnchor = getTraversedLink( text, i + 1, end );
+ }
- traverseSectionBlocks();
+ sink.link( linkAnchor );
+ }
+ else
+ {
+ anchor = true;
+ flushTraversed( buffer, sink );
+ sink.anchor( getTraversedAnchor( text, i + 1, end ) );
+ }
+ }
+ else
+ {
+ buffer.append( c );
+ }
+ break;
- while ( block != null )
- {
- if ( block.getType() <= type )
- {
- break;
- }
+ case /*{*/RIGHT_CURLY_BRACKET:
+ if ( link && i + 1 < end && text.charAt( i + 1 ) == /*{*/RIGHT_CURLY_BRACKET )
+ {
+ ++i;
+ link = false;
+ flushTraversed( buffer, sink );
+ sink.link_();
+ }
+ else if ( anchor )
+ {
+ anchor = false;
+ flushTraversed( buffer, sink );
+ sink.anchor_();
+ }
+ else
+ {
+ buffer.append( c );
+ }
+ break;
- traverseSection( level + 1 );
+ case LESS_THAN:
+ if ( !italic && !bold && !monospaced )
+ {
+ if ( i + 1 < end && text.charAt( i + 1 ) == LESS_THAN )
+ {
+ if ( i + 2 < end && text.charAt( i + 2 ) == LESS_THAN )
+ {
+ i += 2;
+ monospaced = true;
+ flushTraversed( buffer, sink );
+ sink.monospaced();
+ }
+ else
+ {
+ ++i;
+ bold = true;
+ flushTraversed( buffer, sink );
+ sink.bold();
+ }
+ }
+ else
+ {
+ italic = true;
+ flushTraversed( buffer, sink );
+ sink.italic();
+ }
+ }
+ else
+ {
+ buffer.append( c );
+ }
+ break;
+
+ case GREATER_THAN:
+ if ( monospaced && i + 2 < end && text.charAt( i + 1 ) == GREATER_THAN
+ && text.charAt( i + 2 ) == GREATER_THAN )
+ {
+ i += 2;
+ monospaced = false;
+ flushTraversed( buffer, sink );
+ sink.monospaced_();
+ }
+ else if ( bold && i + 1 < end && text.charAt( i + 1 ) == GREATER_THAN )
+ {
+ ++i;
+ bold = false;
+ flushTraversed( buffer, sink );
+ sink.bold_();
+ }
+ else if ( italic )
+ {
+ italic = false;
+ flushTraversed( buffer, sink );
+ sink.italic_();
+ }
+ else
+ {
+ buffer.append( c );
+ }
+ break;
+
+ default:
+ if ( Character.isWhitespace( c ) )
+ {
+ buffer.append( SPACE );
+
+ // Skip to the last char of a sequence of white spaces.
+ while ( i + 1 < end && Character.isWhitespace( text.charAt( i + 1 ) ) )
+ {
+ ++i;
+ }
+ }
+ else
+ {
+ buffer.append( c );
+ }
+ }
}
- switch ( level )
+ if ( monospaced )
{
- case 0:
- sink.section1_();
- break;
- case 1:
- sink.section2_();
- break;
- case 2:
- sink.section3_();
- break;
- case 3:
- sink.section4_();
- break;
- case 4:
- sink.section5_();
- break;
- default:
- break;
+ throw new AptParseException( "missing '" + MONOSPACED_END_MARKUP + "'" );
+ }
+ if ( bold )
+ {
+ throw new AptParseException( "missing '" + BOLD_END_MARKUP + "'" );
+ }
+ if ( italic )
+ {
+ throw new AptParseException( "missing '" + ITALIC_END_MARKUP + "'" );
}
+ if ( link )
+ {
+ throw new AptParseException( "missing '" + LINK_END_MARKUP + "'" );
+ }
+ if ( anchor )
+ {
+ throw new AptParseException( "missing '" + ANCHOR_END_MARKUP + "'" );
+ }
+
+ flushTraversed( buffer, sink );
}
+ // -----------------------------------------------------------------------
+
/**
- * Parse the section blocks of the Apt source document.
+ * Returns the character at position i of the given string.
*
- * @throws AptParseException if something goes wrong.
+ * @param string the string.
+ * @param length length.
+ * @param i offset.
+ * @return the character, or '\0' if i > length.
*/
- private void traverseSectionBlocks()
- throws AptParseException
+ protected static char charAt( String string, int length, int i )
{
- loop: while ( block != null )
+ return ( i < length ) ? string.charAt( i ) : '\0';
+ }
+
+ /**
+ * Skip spaces.
+ *
+ * @param string string.
+ * @param length length.
+ * @param i offset.
+ * @return int.
+ */
+ protected static int skipSpace( String string, int length, int i )
+ {
+ loop: for ( ; i < length; ++i )
{
- switch ( block.getType() )
+ switch ( string.charAt( i ) )
{
- case PARAGRAPH:
- case VERBATIM:
- case FIGURE:
- case TABLE:
- case HORIZONTAL_RULE:
- case PG_BREAK:
- case MACRO:
- case COMMENT_BLOCK:
- block.traverse();
- nextBlock();
- break;
-
- case LIST_ITEM:
- traverseList();
- break;
-
- case NUMBERED_LIST_ITEM:
- traverseNumberedList();
- break;
-
- case DEFINITION_LIST_ITEM:
- traverseDefinitionList();
- break;
-
- case LIST_BREAK:
- // May be this is a list break which has not been indented
- // very precisely.
- nextBlock();
+ case SPACE:
+ case TAB:
break;
-
default:
- // A section block which starts a new section.
break loop;
}
}
+ return i;
}
/**
- * Parse a list of the Apt source document.
+ * Replace part of a string.
*
- * @throws AptParseException if something goes wrong.
+ * @param string the string
+ * @param oldSub the substring to replace
+ * @param newSub the replacement string
+ * @return String
*/
- private void traverseList()
- throws AptParseException
+ protected static String replaceAll( String string, String oldSub, String newSub )
{
- if ( block == null )
+ StringBuffer replaced = new StringBuffer();
+ int oldSubLength = oldSub.length();
+ int begin, end;
+
+ begin = 0;
+ while ( ( end = string.indexOf( oldSub, begin ) ) >= 0 )
{
- return;
+ if ( end > begin )
+ {
+ replaced.append( string.substring( begin, end ) );
+ }
+ replaced.append( newSub );
+ begin = end + oldSubLength;
+ }
+ if ( begin < string.length() )
+ {
+ replaced.append( string.substring( begin ) );
}
- expectedBlock( LIST_ITEM );
-
- int listIndent = block.getIndent();
-
- sink.list();
-
- sink.listItem();
+ return replaced.toString();
+ }
- block.traverse();
+ // ----------------------------------------------------------------------
+ // Private methods
+ // ----------------------------------------------------------------------
- nextBlock();
+ /**
+ * Parse the head of the Apt source document.
+ *
+ * @throws AptParseException if something goes wrong.
+ */
+ private void traverseHead()
+ throws AptParseException
+ {
+ sink.head();
- loop: while ( block != null )
+ if ( block != null && block.getType() == TITLE )
{
- int blockIndent = block.getIndent();
+ block.traverse();
+ nextBlock();
+ }
- switch ( block.getType() )
- {
+ sink.head_();
+ }
+
+ /**
+ * Parse the body of the Apt source document.
+ *
+ * @throws AptParseException if something goes wrong.
+ */
+ private void traverseBody()
+ throws AptParseException
+ {
+ sink.body();
+
+ if ( block != null )
+ {
+ traverseSectionBlocks();
+ }
+
+ while ( block != null )
+ {
+ traverseSection( 0 );
+ }
+
+ sink.body_();
+ }
+
+ /**
+ * Parse a section of the Apt source document.
+ *
+ * @param level The section level.
+ * @throws AptParseException if something goes wrong.
+ */
+ private void traverseSection( int level )
+ throws AptParseException
+ {
+ if ( block == null )
+ {
+ return;
+ }
+
+ int type = SECTION1 + level;
+
+ expectedBlock( type );
+
+ switch ( level )
+ {
+ case 0:
+ sink.section1();
+ break;
+ case 1:
+ sink.section2();
+ break;
+ case 2:
+ sink.section3();
+ break;
+ case 3:
+ sink.section4();
+ break;
+ case 4:
+ sink.section5();
+ break;
+ default:
+ break;
+ }
+
+ block.traverse();
+
+ nextBlock();
+
+ traverseSectionBlocks();
+
+ while ( block != null )
+ {
+ if ( block.getType() <= type )
+ {
+ break;
+ }
+
+ traverseSection( level + 1 );
+ }
+
+ switch ( level )
+ {
+ case 0:
+ sink.section1_();
+ break;
+ case 1:
+ sink.section2_();
+ break;
+ case 2:
+ sink.section3_();
+ break;
+ case 3:
+ sink.section4_();
+ break;
+ case 4:
+ sink.section5_();
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Parse the section blocks of the Apt source document.
+ *
+ * @throws AptParseException if something goes wrong.
+ */
+ private void traverseSectionBlocks()
+ throws AptParseException
+ {
+ loop: while ( block != null )
+ {
+ switch ( block.getType() )
+ {
+ case PARAGRAPH:
+ case VERBATIM:
+ case FIGURE:
+ case TABLE:
+ case HORIZONTAL_RULE:
+ case PG_BREAK:
+ case MACRO:
+ case COMMENT_BLOCK:
+ block.traverse();
+ nextBlock();
+ break;
+
+ case LIST_ITEM:
+ traverseList();
+ break;
+
+ case NUMBERED_LIST_ITEM:
+ traverseNumberedList();
+ break;
+
+ case DEFINITION_LIST_ITEM:
+ traverseDefinitionList();
+ break;
+
+ case LIST_BREAK:
+ // May be this is a list break which has not been indented
+ // very precisely.
+ nextBlock();
+ break;
+
+ default:
+ // A section block which starts a new section.
+ break loop;
+ }
+ }
+ }
+
+ /**
+ * Parse a list of the Apt source document.
+ *
+ * @throws AptParseException if something goes wrong.
+ */
+ private void traverseList()
+ throws AptParseException
+ {
+ if ( block == null )
+ {
+ return;
+ }
+
+ expectedBlock( LIST_ITEM );
+
+ int listIndent = block.getIndent();
+
+ sink.list();
+
+ sink.listItem();
+
+ block.traverse();
+
+ nextBlock();
+
+ loop: while ( block != null )
+ {
+ int blockIndent = block.getIndent();
+
+ switch ( block.getType() )
+ {
case PARAGRAPH:
if ( blockIndent < listIndent )
{
@@ -774,17 +1177,6 @@
}
/**
- * Parse the next line of the Apt source document.
- *
- * @throws AptParseException if something goes wrong.
- */
- private void nextLine()
- throws AptParseException
- {
- line = source.getNextLine();
- }
-
- /**
* Parse the next block of the Apt source document.
*
* @throws AptParseException if something goes wrong.
@@ -836,551 +1228,197 @@
{
nextLine();
}
- }
-
- blockFileName = source.getName();
- blockLineNumber = source.getLineNumber();
- block = null;
- switch ( line.charAt( i ) )
- {
- case STAR:
- if ( indent == 0 )
- {
- if ( charAt( line, length, i + 1 ) == MINUS && charAt( line, length, i + 2 ) == MINUS )
- {
- block = new Table( indent, line );
- }
- else if ( charAt( line, length, i + 1 ) == STAR )
- {
- if ( charAt( line, length, i + 2 ) == STAR )
- {
- if ( charAt( line, length, i + 3 ) == STAR )
- {
- block = new Section5( indent, line );
- }
- else
- {
- block = new Section4( indent, line );
- }
- }
- else
- {
- block = new Section3( indent, line );
- }
- }
- else
- {
- block = new Section2( indent, line );
- }
- }
- else
- {
- block = new ListItem( indent, line );
- }
- break;
- case LEFT_SQUARE_BRACKET:
- if ( charAt( line, length, i + 1 ) == RIGHT_SQUARE_BRACKET )
- {
- block = new ListBreak( indent, line );
- }
- else
- {
- if ( indent == 0 )
- {
- block = new Figure( indent, line );
- }
- else
- {
- if ( charAt( line, length, i + 1 ) == LEFT_SQUARE_BRACKET )
- {
- int numbering;
-
- switch ( charAt( line, length, i + 2 ) )
- {
- case NUMBERING_LOWER_ALPHA_CHAR:
- numbering = Sink.NUMBERING_LOWER_ALPHA;
- break;
- case NUMBERING_UPPER_ALPHA_CHAR:
- numbering = Sink.NUMBERING_UPPER_ALPHA;
- break;
- case NUMBERING_LOWER_ROMAN_CHAR:
- numbering = Sink.NUMBERING_LOWER_ROMAN;
- break;
- case NUMBERING_UPPER_ROMAN_CHAR:
- numbering = Sink.NUMBERING_UPPER_ROMAN;
- break;
- case NUMBERING:
- default:
- // The first item establishes the numbering
- // scheme for the whole list.
- numbering = Sink.NUMBERING_DECIMAL;
- }
-
- block = new NumberedListItem( indent, line, numbering );
- }
- else
- {
- block = new DefinitionListItem( indent, line );
- }
- }
- }
- break;
- case MINUS:
- if ( charAt( line, length, i + 1 ) == MINUS && charAt( line, length, i + 2 ) == MINUS )
- {
- if ( indent == 0 )
- {
- block = new Verbatim( indent, line );
- }
- else
- {
- if ( firstBlock )
- {
- block = new Title( indent, line );
- }
- }
- }
- break;
- case PLUS:
- if ( indent == 0 && charAt( line, length, i + 1 ) == MINUS && charAt( line, length, i + 2 ) == MINUS )
- {
- block = new Verbatim( indent, line );
- }
- break;
- case EQUAL:
- if ( indent == 0 && charAt( line, length, i + 1 ) == EQUAL && charAt( line, length, i + 2 ) == EQUAL )
- {
- block = new HorizontalRule( indent, line );
- }
- break;
- case PAGE_BREAK:
- if ( indent == 0 )
- {
- block = new PageBreak( indent, line );
- }
- break;
- case PERCENT:
- if ( indent == 0 && charAt( line, length, i + 1 ) == LEFT_CURLY_BRACKET )
- {
- block = new MacroBlock( indent, line );
- }
- break;
- case COMMENT:
- if ( indent == 0 && charAt( line, length, i + 1 ) == COMMENT )
- {
- block = new Comment( line.substring( 2 ).trim() );
- }
- break;
- default:
- break;
- }
-
- if ( block == null )
- {
- if ( indent == 0 )
- {
- block = new Section1( indent, line );
- }
- else
- {
- block = new Paragraph( indent, line );
- }
- }
- }
-
- /**
- * Checks that the current block is of the expected type.
- *
- * @param type the expected type.
- * @throws AptParseException if something goes wrong.
- */
- private void expectedBlock( int type )
- throws AptParseException
- {
- int blockType = block.getType();
-
- if ( blockType != type )
- {
- throw new AptParseException( "expected " + TYPE_NAMES[type] + ", found " + TYPE_NAMES[blockType] );
- }
- }
-
- // -----------------------------------------------------------------------
-
- /**
- * Determin if c is an octal character.
- *
- * @param c the character.
- * @return boolean
- */
- private static boolean isOctalChar( char c )
- {
- return ( c >= '0' && c <= '7' );
- }
-
- /**
- * Determin if c is an hex character.
- *
- * @param c the character.
- * @return boolean
- */
- private static boolean isHexChar( char c )
- {
- return ( ( c >= '0' && c <= '9' ) || ( c >= 'a' && c <= 'f' ) || ( c >= 'A' && c <= 'F' ) );
- }
-
- /**
- * Returns the character at position i of the given string.
- *
- * @param string the string.
- * @param length length.
- * @param i offset.
- * @return the character, or '\0' if i > length.
- */
- private static char charAt( String string, int length, int i )
- {
- return ( i < length ) ? string.charAt( i ) : '\0';
- }
-
- /**
- * Skip spaces.
- *
- * @param string string.
- * @param length length.
- * @param i offset.
- * @return int.
- */
- private static int skipSpace( String string, int length, int i )
- {
- loop: for ( ; i < length; ++i )
- {
- switch ( string.charAt( i ) )
- {
- case SPACE:
- case TAB:
- break;
- default:
- break loop;
- }
- }
- return i;
- }
-
- /**
- * Parse the given text.
- *
- * @param text the text to parse.
- * @param begin offset.
- * @param end offset.
- * @param sink the sink to receive the events.
- * @throws AptParseException if something goes wrong.
- */
- private void doTraverseText( String text, int begin, int end, Sink sink )
- throws AptParseException
- {
- boolean anchor = false;
- boolean link = false;
- boolean italic = false;
- boolean bold = false;
- boolean monospaced = false;
- StringBuffer buffer = new StringBuffer( end - begin );
-
- for ( int i = begin; i < end; ++i )
- {
- char c = text.charAt( i );
- switch ( c )
- {
- case BACKSLASH:
- if ( i + 1 < end )
- {
- char escaped = text.charAt( i + 1 );
- switch ( escaped )
- {
- case SPACE:
- ++i;
- flushTraversed( buffer, sink );
- sink.nonBreakingSpace();
- break;
- case '\r':
- case '\n':
- ++i;
- // Skip white space which may follow a line break.
- while ( i + 1 < end && Character.isWhitespace( text.charAt( i + 1 ) ) )
- {
- ++i;
- }
- flushTraversed( buffer, sink );
- sink.lineBreak();
- break;
- case BACKSLASH:
- case PIPE:
- case COMMENT:
- case EQUAL:
- case MINUS:
- case PLUS:
- case STAR:
- case LEFT_SQUARE_BRACKET:
- case RIGHT_SQUARE_BRACKET:
- case LESS_THAN:
- case GREATER_THAN:
- case LEFT_CURLY_BRACKET:
- case RIGHT_CURLY_BRACKET:
- ++i;
- buffer.append( escaped );
- break;
- case 'x':
- if ( i + 3 < end && isHexChar( text.charAt( i + 2 ) )
- && isHexChar( text.charAt( i + 3 ) ) )
- {
- int value = '?';
- try
- {
- value = Integer.parseInt( text.substring( i + 2, i + 4 ), 16 );
- }
- catch ( NumberFormatException e )
- {
- if ( getLog().isDebugEnabled() )
- {
- getLog().debug( "Not a number: " + text.substring( i + 2, i + 4 ) );
- }
- }
-
- i += 3;
- buffer.append( (char) value );
- }
- else
- {
- buffer.append( BACKSLASH );
- }
- break;
- case 'u':
- if ( i + 5 < end && isHexChar( text.charAt( i + 2 ) )
- && isHexChar( text.charAt( i + 3 ) ) && isHexChar( text.charAt( i + 4 ) )
- && isHexChar( text.charAt( i + 5 ) ) )
- {
- int value = '?';
- try
- {
- value = Integer.parseInt( text.substring( i + 2, i + 6 ), 16 );
- }
- catch ( NumberFormatException e )
- {
- if ( getLog().isDebugEnabled() )
- {
- getLog().debug( "Not a number: " + text.substring( i + 2, i + 6 ) );
- }
- }
-
- i += 5;
- buffer.append( (char) value );
- }
- else
- {
- buffer.append( BACKSLASH );
- }
- break;
- default:
- if ( isOctalChar( escaped ) )
- {
- int octalChars = 1;
- if ( isOctalChar( charAt( text, end, i + 2 ) ) )
- {
- ++octalChars;
- if ( isOctalChar( charAt( text, end, i + 3 ) ) )
- {
- ++octalChars;
- }
- }
- int value = '?';
- try
- {
- value = Integer.parseInt( text.substring( i + 1, i + 1 + octalChars ), 8 );
- }
- catch ( NumberFormatException e )
- {
- if ( getLog().isDebugEnabled() )
- {
- getLog().debug(
- "Not a number: "
- + text.substring( i + 1, i + 1 + octalChars ) );
- }
- }
-
- i += octalChars;
- buffer.append( (char) value );
- }
- else
- {
- buffer.append( BACKSLASH );
- }
- }
- }
- else
- {
- buffer.append( BACKSLASH );
- }
- break;
-
- case LEFT_CURLY_BRACKET: /*}*/
- if ( !anchor && !link )
- {
- if ( i + 1 < end && text.charAt( i + 1 ) == LEFT_CURLY_BRACKET /*}*/)
- {
- ++i;
- link = true;
- flushTraversed( buffer, sink );
-
- String linkAnchor = null;
-
- if ( i + 1 < end && text.charAt( i + 1 ) == LEFT_CURLY_BRACKET /*}*/)
- {
- ++i;
- StringBuffer buf = new StringBuffer();
- i = skipTraversedLinkAnchor( text, i + 1, end, buf );
- linkAnchor = buf.toString();
- }
-
- if ( linkAnchor == null )
- {
- linkAnchor = getTraversedLink( text, i + 1, end );
- }
-
- sink.link( linkAnchor );
- }
- else
- {
- anchor = true;
- flushTraversed( buffer, sink );
- sink.anchor( getTraversedAnchor( text, i + 1, end ) );
- }
- }
- else
- {
- buffer.append( c );
- }
- break;
-
- case /*{*/RIGHT_CURLY_BRACKET:
- if ( link && i + 1 < end && text.charAt( i + 1 ) == /*{*/RIGHT_CURLY_BRACKET )
- {
- ++i;
- link = false;
- flushTraversed( buffer, sink );
- sink.link_();
- }
- else if ( anchor )
- {
- anchor = false;
- flushTraversed( buffer, sink );
- sink.anchor_();
- }
- else
+ }
+
+ blockFileName = source.getName();
+ blockLineNumber = source.getLineNumber();
+ block = null;
+ switch ( line.charAt( i ) )
+ {
+ case STAR:
+ if ( indent == 0 )
+ {
+ if ( charAt( line, length, i + 1 ) == MINUS && charAt( line, length, i + 2 ) == MINUS )
{
- buffer.append( c );
+ block = new Table( indent, line );
}
- break;
-
- case LESS_THAN:
- if ( !italic && !bold && !monospaced )
+ else if ( charAt( line, length, i + 1 ) == STAR )
{
- if ( i + 1 < end && text.charAt( i + 1 ) == LESS_THAN )
+ if ( charAt( line, length, i + 2 ) == STAR )
{
- if ( i + 2 < end && text.charAt( i + 2 ) == LESS_THAN )
+ if ( charAt( line, length, i + 3 ) == STAR )
{
- i += 2;
- monospaced = true;
- flushTraversed( buffer, sink );
- sink.monospaced();
+ block = new Section5( indent, line );
}
else
{
- ++i;
- bold = true;
- flushTraversed( buffer, sink );
- sink.bold();
+ block = new Section4( indent, line );
}
}
else
{
- italic = true;
- flushTraversed( buffer, sink );
- sink.italic();
+ block = new Section3( indent, line );
}
}
else
{
- buffer.append( c );
- }
- break;
-
- case GREATER_THAN:
- if ( monospaced && i + 2 < end && text.charAt( i + 1 ) == GREATER_THAN
- && text.charAt( i + 2 ) == GREATER_THAN )
- {
- i += 2;
- monospaced = false;
- flushTraversed( buffer, sink );
- sink.monospaced_();
- }
- else if ( bold && i + 1 < end && text.charAt( i + 1 ) == GREATER_THAN )
- {
- ++i;
- bold = false;
- flushTraversed( buffer, sink );
- sink.bold_();
+ block = new Section2( indent, line );
}
- else if ( italic )
+ }
+ else
+ {
+ block = new ListItem( indent, line );
+ }
+ break;
+ case LEFT_SQUARE_BRACKET:
+ if ( charAt( line, length, i + 1 ) == RIGHT_SQUARE_BRACKET )
+ {
+ block = new ListBreak( indent, line );
+ }
+ else
+ {
+ if ( indent == 0 )
{
- italic = false;
- flushTraversed( buffer, sink );
- sink.italic_();
+ block = new Figure( indent, line );
}
else
{
- buffer.append( c );
- }
- break;
+ if ( charAt( line, length, i + 1 ) == LEFT_SQUARE_BRACKET )
+ {
+ int numbering;
- default:
- if ( Character.isWhitespace( c ) )
- {
- buffer.append( SPACE );
+ switch ( charAt( line, length, i + 2 ) )
+ {
+ case NUMBERING_LOWER_ALPHA_CHAR:
+ numbering = Sink.NUMBERING_LOWER_ALPHA;
+ break;
+ case NUMBERING_UPPER_ALPHA_CHAR:
+ numbering = Sink.NUMBERING_UPPER_ALPHA;
+ break;
+ case NUMBERING_LOWER_ROMAN_CHAR:
+ numbering = Sink.NUMBERING_LOWER_ROMAN;
+ break;
+ case NUMBERING_UPPER_ROMAN_CHAR:
+ numbering = Sink.NUMBERING_UPPER_ROMAN;
+ break;
+ case NUMBERING:
+ default:
+ // The first item establishes the numbering
+ // scheme for the whole list.
+ numbering = Sink.NUMBERING_DECIMAL;
+ }
- // Skip to the last char of a sequence of white spaces.
- while ( i + 1 < end && Character.isWhitespace( text.charAt( i + 1 ) ) )
+ block = new NumberedListItem( indent, line, numbering );
+ }
+ else
{
- ++i;
+ block = new DefinitionListItem( indent, line );
}
}
+ }
+ break;
+ case MINUS:
+ if ( charAt( line, length, i + 1 ) == MINUS && charAt( line, length, i + 2 ) == MINUS )
+ {
+ if ( indent == 0 )
+ {
+ block = new Verbatim( indent, line );
+ }
else
{
- buffer.append( c );
+ if ( firstBlock )
+ {
+ block = new Title( indent, line );
+ }
}
- }
+ }
+ break;
+ case PLUS:
+ if ( indent == 0 && charAt( line, length, i + 1 ) == MINUS && charAt( line, length, i + 2 ) == MINUS )
+ {
+ block = new Verbatim( indent, line );
+ }
+ break;
+ case EQUAL:
+ if ( indent == 0 && charAt( line, length, i + 1 ) == EQUAL && charAt( line, length, i + 2 ) == EQUAL )
+ {
+ block = new HorizontalRule( indent, line );
+ }
+ break;
+ case PAGE_BREAK:
+ if ( indent == 0 )
+ {
+ block = new PageBreak( indent, line );
+ }
+ break;
+ case PERCENT:
+ if ( indent == 0 && charAt( line, length, i + 1 ) == LEFT_CURLY_BRACKET )
+ {
+ block = new MacroBlock( indent, line );
+ }
+ break;
+ case COMMENT:
+ if ( indent == 0 && charAt( line, length, i + 1 ) == COMMENT )
+ {
+ block = new Comment( line.substring( 2 ).trim() );
+ }
+ break;
+ default:
+ break;
}
- if ( monospaced )
- {
- throw new AptParseException( "missing '" + MONOSPACED_END_MARKUP + "'" );
- }
- if ( bold )
- {
- throw new AptParseException( "missing '" + BOLD_END_MARKUP + "'" );
- }
- if ( italic )
- {
- throw new AptParseException( "missing '" + ITALIC_END_MARKUP + "'" );
- }
- if ( link )
+ if ( block == null )
{
- throw new AptParseException( "missing '" + LINK_END_MARKUP + "'" );
+ if ( indent == 0 )
+ {
+ block = new Section1( indent, line );
+ }
+ else
+ {
+ block = new Paragraph( indent, line );
+ }
}
- if ( anchor )
+ }
+
+ /**
+ * Checks that the current block is of the expected type.
+ *
+ * @param type the expected type.
+ * @throws AptParseException if something goes wrong.
+ */
+ private void expectedBlock( int type )
+ throws AptParseException
+ {
+ int blockType = block.getType();
+
+ if ( blockType != type )
{
- throw new AptParseException( "missing '" + ANCHOR_END_MARKUP + "'" );
+ throw new AptParseException( "expected " + TYPE_NAMES[type] + ", found " + TYPE_NAMES[blockType] );
}
+ }
- flushTraversed( buffer, sink );
+ // -----------------------------------------------------------------------
+
+ /**
+ * Determine if c is an octal character.
+ *
+ * @param c the character.
+ * @return boolean
+ */
+ private static boolean isOctalChar( char c )
+ {
+ return ( c >= '0' && c <= '7' );
+ }
+
+ /**
+ * Determine if c is an hex character.
+ *
+ * @param c the character.
+ * @return boolean
+ */
+ private static boolean isHexChar( char c )
+ {
+ return ( ( c >= '0' && c <= '9' ) || ( c >= 'a' && c <= 'f' ) || ( c >= 'A' && c <= 'F' ) );
}
/**
@@ -1526,16 +1564,19 @@
Sink linkSink = new SinkAdapter()
{
+ /** {@inheritDoc} */
public void lineBreak()
{
buffer.append( SPACE );
}
+ /** {@inheritDoc} */
public void nonBreakingSpace()
{
buffer.append( SPACE );
}
+ /** {@inheritDoc} */
public void text( String text )
{
buffer.append( text );
@@ -2828,39 +2869,5 @@
return result;
}
- }
-
- // -----------------------------------------------------------------------
-
- /**
- * Replace part of a string.
- *
- * @param string the string
- * @param oldSub the substring to replace
- * @param newSub the replacement string
- * @return String
- */
- private static String replaceAll( String string, String oldSub, String newSub )
- {
- StringBuffer replaced = new StringBuffer();
- int oldSubLength = oldSub.length();
- int begin, end;
-
- begin = 0;
- while ( ( end = string.indexOf( oldSub, begin ) ) >= 0 )
- {
- if ( end > begin )
- {
- replaced.append( string.substring( begin, end ) );
- }
- replaced.append( newSub );
- begin = end + oldSubLength;
- }
- if ( begin < string.length() )
- {
- replaced.append( string.substring( begin ) );
- }
-
- return replaced.toString();
}
}