/* * [ManipulateMacros.java] * * Summary: Methods for tidying macros. * * Copyright: (c) 2012-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.0 2012-03-14 initial version */ package com.mindprod.stores; import com.mindprod.common18.ST; import java.io.File; import static java.lang.System.*; /** * Methods for tidying macros. * * @author Roedy Green, Canadian Mind Products * @version 1.0 2012-03-14 initial version * @see com.mindprod.stores.TidyElectronicMacros * @since 2012-03-14 */ public class ManipulateMacros { /** * max chars on a reflowed line */ private static final int MAX_FLOW_LENGTH = 120; /** * insert key=value into the corresponding macro, checks if key= already present * * @param contents contents of entire file * @param macro name of macro to insert into * @param key keyword to insert * @param value without {} or "". empty does nothing * @param fileInsertingInto file we are inserting into. We don't touch the file, * just use its name for error messages. * * @return contents with inserted key=value */ protected static String appendToCommaList( final String contents, final String macro, final String key, final String value, final File fileInsertingInto ) { // insert key=value at head of macro. if ( ST.isEmpty( value ) ) { return contents; } final String oneMacro = findFirstMacroContents( contents, macro ); if ( oneMacro == null ) { err.println( "Missing ", start ); if ( end < 0 ) { return null; } else { return contents.substring( start, end ).replaceAll( "\\s+", " " ); } } } /** * find values of parm of the form xxx="..." or xxx={...} * THIS IS A VERY PRIMITIVE PARSER. IT COULD BE FOOLED BY ebook=xxx inside the notes={xxxx} field. * * @param oneMacro text in which to search for parms, one Book macro. * @param keyname name of param to search for, case-sensitive * * @return value of the parm. null if missing, "" if empty. Strips enclosing {} or "". */ protected static String parseValueByKey( String oneMacro, String keyname ) { int start = oneMacro.indexOf( keyname + "=" ); if ( start < 0 ) { return null; // indicate no such parm } final int size = oneMacro.length(); start += keyname.length() + 1; if ( start >= size ) { throw new IllegalArgumentException( "Truncated parm= : " + keyname ); } final char c = oneMacro.charAt( start ); final int end; switch ( c ) { case ' ': start++; if ( start >= size ) { throw new IllegalArgumentException( "Truncated parm= : " + keyname ); } end = oneMacro.indexOf( ' ', start ); if ( end == start ) { throw new IllegalArgumentException( "Malformed parm= : " + keyname ); } break; case '\"': start++; if ( start >= size ) { throw new IllegalArgumentException( "Truncated parm= : " + keyname ); } end = oneMacro.indexOf( '\"', start ); break; case '{': start++; if ( start >= size ) { throw new IllegalArgumentException( "Truncated parm= : " + keyname ); } end = oneMacro.indexOf( '}', start ); break; default: // e.g. birth=1948-02-04 end = oneMacro.indexOf( ' ', start ); break; } if ( end < 0 ) { throw new IllegalArgumentException( "Malformed parm= missing terminator : " + keyname ); } // trim of surrounding {} "" return oneMacro.substring( start, end ).trim(); } /** * reflow text * * @param s HTML text to reflow, one long line, no Cr Lf or doubled spaces. * * @return HTML text reflowed into lines of MAX_FLOW_LENGTH chars */ protected static String reflow( String s ) { if ( s == null ) { return null; } s = s.trim(); if ( s.length() <= MAX_FLOW_LENGTH ) { return s; } int lineLength = 0; final StringBuilder sb = new StringBuilder( s.length() ); for ( int i = 0; i < s.length(); i++ ) { final char c = s.charAt( i ); switch ( c ) { case '<': { final String coming = s.substring( i + 1 ); // tags that start a new line. if ( coming.startsWith( "blockquote" ) || coming.startsWith( "br" ) || coming.startsWith( "div" ) || coming.startsWith( "li" ) || coming.startsWith( "ol" ) || coming.startsWith( "p" ) || coming.startsWith( "table" ) || coming.startsWith( "td" ) || coming.startsWith( "th" ) || coming.startsWith( "tr" ) || coming.startsWith( "ul" ) ) { sb.append( "\n<" ); lineLength = 1; } else { // just ordinary < sb.append( "<" ); lineLength++; } break; } case ' ': { if ( i + 1 >= s.length() ) { // this is the last char, ignore the space. break; } // look for next space int nextSpace = s.indexOf( ' ', i + 1 ); if ( nextSpace < 0 ) { nextSpace = s.length(); //fake a space after end of string. } if ( nextSpace - i + lineLength > MAX_FLOW_LENGTH ) { sb.append( '\n' ); lineLength = 0; } else { sb.append( ' ' ); lineLength++; } break; } default: { sb.append( c ); lineLength++; } } // end switch } // end for return sb.toString(); } }