/* * [AnnotateColours.java] * * Summary: Annotates hex colour references in Style sheets with colour names. * * 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.0 2009-04-13 initial release */ package com.mindprod.repair; import com.mindprod.commandline.CommandLine; import com.mindprod.common18.EIO; import com.mindprod.common18.Misc; import com.mindprod.csv.CSVReader; import com.mindprod.fastcat.FastCat; import com.mindprod.filter.AllButSVNDirectoriesFilter; import com.mindprod.filter.ExtensionListFilter; import com.mindprod.htmlmacros.macro.Global; import com.mindprod.htmlmacros.support.ConfigurationForMindprod; import com.mindprod.hunkio.HunkIO; import java.io.BufferedReader; import java.io.EOFException; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import static java.lang.System.*; /** * Annotates hex colour references in Style sheets with colour names. *

* Used after ExtractColours and assigning names to unnamed colours. * * @author Roedy Green, Canadian Mind Products * @version 1.0 2009-04-13 initial release * @see ExtractColours * @since 2009-04-13 */ public class AnnotateColours { private static final int FIRST_COPYRIGHT_YEAR = 2009; /** * undisplayed copyright notice */ @SuppressWarnings( { "UnusedDeclaration" } ) private static final String EMBEDDED_COPYRIGHT = "Copyright: (c) 2009-2017 Roedy Green, Canadian Mind Products, http://mindprod.com"; /** * how to use the command line */ private static final String USAGE = "\nAnnotateColours needs a space-separated list of filename.csv with optional " + "-s -q -v switches, Run annotatecolours.btm not annotatecolours.exe."; /** * regex to find annotation comments in a style sheet */ private static final Pattern COLOUR_COMMENT_PATTERN = Pattern.compile( "/\\*![\\p{Alnum}, \\+\\-]+!\\*/" ); /** * regex to look for hex colour numbers in a style sheet */ private static final Pattern HEX_COLOUR_NUMBER_PATTERN = Pattern.compile( "(;|#\\p{XDigit}{6})" ); /** * track down colours and their descriptions */ private static final TreeMap knownColours = new TreeMap<>(); /** * name of file to read csv colour/description pairs */ private static File csvInput; /** * extract unknown colours from the style sheets on the command line * * @param args command line list of style sheets * * @throws java.io.IOException if trouble reading style sheets */ private static void annotateColoursWithComments( final String[] args ) throws IOException { CommandLine commandLine = new CommandLine( args, new AllButSVNDirectoriesFilter(), new ExtensionListFilter( "css" ) ); if ( commandLine.size() == 0 ) { throw new IllegalArgumentException( "No files found to process" + USAGE ); } for ( File file : commandLine ) { final String contents = HunkIO.readEntireFile( file, HunkIO.UTF8 ); // must be StringBuffer to be compatible with Matcher. StringBuffer sb = new StringBuffer( contents.length() * 130 / 100 ); final Matcher m = HEX_COLOUR_NUMBER_PATTERN.matcher( contents ); ArrayList descs = new ArrayList<>( 4 ); while ( m.find() ) { // we found either a hex colour number or a semicolon, # already stripped final String token = m.group( 1 ); final boolean isSemicolon = token.equals( ";" ); if ( isSemicolon ) { // insert comment just after semicolon if there were colours to annotate on the line. if ( descs.size() > 0 ) { FastCat sb2 = new FastCat( descs.size() * 2 + 2 ); sb2.append( "; /*! " ); for ( String desc : descs ) { sb2.append( desc ); sb2.append( ", " ); } sb2.drop(); // remove trailing comma sb2.append( " !*/" ); final String commentToInsert = sb2.toString(); m.appendReplacement( sb, commentToInsert ); // no need for Matcher.quoteReplacement descs.clear(); } // if no pending descs, nothing to do } else { // this must have been a colour number in the middle of a line. // just note this colour for later annotation assert token.startsWith( "#" ) : "malformed hex"; final String anotherColour = token.substring( 1 ); final String desc = knownColours.get( anotherColour ); if ( desc == null ) { err.println( "Warning: unknown colour encountered " + anotherColour + " in " + EIO.getCanOrAbsPath( file ) ); } else { descs.add( desc ); } } } // end loop processing fragments of text if ( descs.size() != 0 ) { err.println( "missing semicolon near end of file " + EIO.getCanOrAbsPath( file ) ); descs.clear(); } m.appendTail( sb ); HunkIO.writeEntireFile( file, sb.toString(), HunkIO.UTF8 ); } } /** * read existing list of known colours * * @throws java.io.IOException if trouble reading CSV list of known colours */ private static void readKnownColours() throws IOException { // O P E N final FileReader fr = new FileReader( csvInput ); final BufferedReader br = new BufferedReader( fr, 24 * 1024 /* 24K chars (48K bytes), 75% of allocation is optimal */ ); // reader, separatorChar, quoteChar, commentChars, hideComments, trimQuoted, trimUnquoted, // allowMultipleLineFields final CSVReader r = new CSVReader( br, ',', '\"', "#", true, true /* trimQuoted */, true /* trimUnquoted */, false ); final HashMap dupDescDetector = new HashMap<>( 1000 ); try { //noinspection InfiniteLoopStatement while ( true ) { final String colour = r.get(); if ( colour == null ) { // bypass blank line. continue; } final String desc = r.get(); // lookup by colour final String prevDesc = knownColours.put( colour, desc ); if ( prevDesc != null ) { err.println( "Error: Duplicate entry for colour " + colour + " : " + desc + " : " + prevDesc ); } // lookup by desc final String prevColour = dupDescDetector.put( desc, colour ); if ( prevColour != null ) { err.println( "Warning: Duplicate entry for description " + desc + " : " + colour + " : " + prevColour ); } r.skipToNextLine(); } } catch ( EOFException e ) { r.close(); } } /** * remove existing annotation * * @param args command line list of style sheets * * @throws java.io.IOException if trouble reading style sheets */ private static void removeColourAnnotationComments( final String[] args ) throws IOException { // remove old comment of form: |*! firebrick !*| or |*! Deeks blue, pansy blue !*| CommandLine files = new CommandLine( args, new AllButSVNDirectoriesFilter(), new ExtensionListFilter( "css" ) ); for ( File file : files ) { final String contents = HunkIO.readEntireFile( file, HunkIO.UTF8 ); // must be StringBuffer to be compatible with Matcher, not StringBuilder or FastCat. StringBuffer sb = new StringBuffer( contents.length() ); final Matcher m = COLOUR_COMMENT_PATTERN.matcher( contents ); while ( m.find() ) { // remove the annotation comment just found m.appendReplacement( sb, "" ); // no need for Matcher.quoteReplacement } m.appendTail( sb ); HunkIO.writeEntireFile( file, sb.toString(), HunkIO.UTF8 ); } } /** * Extracts lines in files that contain a given string. * List of all colour names must exist in E:\mindprod\repair\knowncolours.csv. * Will get a list of missing colour names. * * @param args style sheets to scan, e.g. E:\mindprod\mindprod.css */ public static void main( String[] args ) { Global.installConfiguration( new ConfigurationForMindprod() ); csvInput = new File( Global.configuration.getSourceDirWithSlashes(), "repair/knowncolours.csv" ); try { // read existing list of known colours readKnownColours(); // remove existing annotations from all style sheets. removeColourAnnotationComments( args ); // extract unknown colours from the style sheets on the command line annotateColoursWithComments( args ); out.println( "Done" ); } catch ( Exception e ) { e.printStackTrace( err ); err.println(); } Misc.trackLastThread(); System.exit( 0 ); } // end main }