/*
* [Include.java]
*
* Summary: Implements Include macro.
*
* Copyright: (c) 2009-2017 Roedy Green, Canadian Mind Products, http://mindprod.com
*
* Licence: This software may be copied and used freely for any purpose but military.
* http://mindprod.com/contact/nonmil.html
*
* Requires: JDK 1.8+
*
* Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/
*
* Version History:
* 1.8 2009-02-06 include go package in ZIP bundle.
* 1.9 2011-11-21 fileBeingProcessed is now an instance variable rather than a parm.
*/
package com.mindprod.htmlmacros.macro;
import com.mindprod.compactor.Compactor;
import com.mindprod.fastcat.FastCat;
import com.mindprod.htmlmacros.Replacer;
import com.mindprod.htmlmacros.support.LoadCodeToProcessMacro;
import com.mindprod.htmlmacros.support.ParmParser;
import com.mindprod.htmlmacros.support.Tools;
import com.mindprod.hunkio.HunkIO;
import java.io.File;
import java.io.IOException;
import static com.mindprod.htmlmacros.macro.Global.configuration;
import static java.lang.System.*;
/**
* Implements Include macro.
*
* Expands HTML boilerplate macro that simply include from another file e.g. <!-- macro Include dogs.txt
* -->
<!-- generated-->
<!-- /generated by Include -->
It is not this class's duty
* to create the generated and /generated comment tags, just the material between them.
This code is like a stripped
* down version of Replacer. We don't have the complications of: - fixing line separators
- Deciding
* whether to compact or not. We don't. Replacer does it for us.
- Tracking whether to abort. We just throw an
* exception.
- Tracking whether this expansion is different from the existing expansion.
- Writing out
* the results to disk.
*
* Included macro text may be compact or not, and may contain leading or trailing whitespace.
* Replacer deals with COMPACTING if necessary. We pass expansion on without compacting.
* Macros in included text will be expanded, but the macros themselves and the
parseAndExpandMacro( quiet, verbose );
}
else if ( command.equals( "generated" ) )
{
// delete generated through /generated, for any macro
if ( scan( "-->", true ) )
{
copy = false;
}
else
{
throw new IllegalArgumentException( "Syntax error: ", true ) )
{
copy = true;
}
else
{
throw new IllegalArgumentException(
"Syntax error: ", true ) )
{
if ( copy )
{
emit.append( "" );
}
}
}
else
{
// no more comments, just copy tail and we are done.
if ( copy )
{
// tail end
assert 0 <= offset && offset <= originalLength;
emit.append( original.substring( offset ) );
}
break;
}
} // end while
// might shrink if not compact to start.
if ( checkEstimate )
{
emit.checkEstimate();
}
return emit.toString();
}
/**
* Scan from the current offset looking for the next word (delimited by white space) It does not modify chunk or
* offset.
*
* @return next word in original starting at offset.
*/
private String nextWord()
{
// we want to avoid creating needless substrings that could
// be very long, so we process char by char.
boolean inLeading = true;
int start = offset;
for ( int i = offset; i < originalLength; i++ )
{
if ( Character.isWhitespace( original.charAt( i ) ) )
{
if ( inLeading )
{
start = i + 1;
}
else
{
return original.substring( start, i/* one past end */ );
}
}
else
{
inLeading = false;
}
} // end for
return ( original.substring( start ) );
} // end nextWord
/**
* process a macro or nested include of the form:
*
* @param quiet true if want progress messages suppressed
* @param verbose true if want progress log.
*
* @throws ClassNotFoundException if can't find macro, or code does not implement Macro.
* @throws IllegalAccessException if missing public access
* @throws InstantiationException if missing no-arg constructor.
*/
private void parseAndExpandMacro( final boolean quiet, final boolean verbose ) throws
ClassNotFoundException,
IllegalAccessException,
InstantiationException
{
// we found something of the form:
//
// we have parsed up to but not including the word macro
// parse out the various sections.
// has to be ok, since we already found it.
scan( "macro", true );
macroName = nextWord();
// at worst would be empty name
scan( macroName, true );
if ( !scan( "-->", false ) )
{
throw new IllegalArgumentException(
"syntax error missing --> to close macro." );
}
// text between macro and -->
parms = ParmParser.parseParms( chunk.trim() );
// has to be ok, since already found it earlier
scan( "-->", true );
// we remove the " );
return sb.toString();
}
public static void clearNestingDepth()
{
nestingDepth = 0;
}
/**
* Generate macro expansion for Include macro, recursively expands macros including other includes. This is what
* replacer calls start the possibly nested include process off.
*
* @param parms parsed params for the macro, in this case just "filename".
* @param quiet true if want output suppressed.
* @param verbose @return expanded macro HTML
*
* @return text included from some file as result of this macro.
*/
public final String expandMacro( final String[] parms, final boolean quiet, final boolean verbose )
{
if ( !quiet )
{
// indicate we handled an include macro on the console
out.print( "I" );
}
if ( !fileBeingProcessed.equals( prevFileBeingProcessed ) )
{
nestingDepth = 0;
prevFileBeingProcessed = fileBeingProcessed;
}
if ( parms.length != 1 )
{
throw new IllegalArgumentException( USAGE );
}
final String includedFile = parms[ 0 ].replace( '\\', '/' );
//