/* * [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-->
"dog"
<!-- /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:

  1. fixing line separators
  2. Deciding * whether to compact or not. We don't. Replacer does it for us.
  3. Tracking whether to abort. We just throw an * exception.
  4. Tracking whether this expansion is different from the existing expansion.
  5. 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( '\\', '/' ); //