Home | History | Annotate | Download | only in util
      1 /*
      2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
      3  *             of Java bytecode.
      4  *
      5  * Copyright (c) 2002-2014 Eric Lafortune (eric (at) graphics.cornell.edu)
      6  *
      7  * This program is free software; you can redistribute it and/or modify it
      8  * under the terms of the GNU General Public License as published by the Free
      9  * Software Foundation; either version 2 of the License, or (at your option)
     10  * any later version.
     11  *
     12  * This program is distributed in the hope that it will be useful, but WITHOUT
     13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
     15  * more details.
     16  *
     17  * You should have received a copy of the GNU General Public License along
     18  * with this program; if not, write to the Free Software Foundation, Inc.,
     19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
     20  */
     21 package proguard.util;
     22 
     23 import java.util.List;
     24 
     25 /**
     26  * This StringParser can create StringMatcher instances for regular expressions.
     27  * The regular expressions are either presented as a list, or they are
     28  * interpreted as comma-separated lists, optionally prefixed with '!' negators.
     29  * If an entry with a negator matches, a negative match is returned, without
     30  * considering any subsequent entries in the list. The creation of StringMatcher
     31  * instances  for the entries is delegated to the given StringParser.
     32  *
     33  * @author Eric Lafortune
     34  */
     35 public class ListParser implements StringParser
     36 {
     37     private final StringParser stringParser;
     38 
     39 
     40     /**
     41      * Creates a new ListParser that parses individual elements in the
     42      * comma-separated list with the given StringParser.
     43      */
     44     public ListParser(StringParser stringParser)
     45     {
     46         this.stringParser = stringParser;
     47     }
     48 
     49 
     50     // Implementations for StringParser.
     51 
     52     public StringMatcher parse(String regularExpression)
     53     {
     54         // Does the regular expression contain a ',' list separator?
     55         return parse(ListUtil.commaSeparatedList(regularExpression));
     56     }
     57 
     58 
     59     /**
     60      * Creates a StringMatcher for the given regular expression, which can
     61      * be a list of optionally negated simple entries.
     62      * <p>
     63      * An empty list results in a StringMatcher that matches any string.
     64      */
     65     public StringMatcher parse(List regularExpressions)
     66     {
     67         StringMatcher listMatcher = null;
     68 
     69         // Loop over all simple regular expressions, backward, creating a
     70         // linked list of matchers.
     71         for (int index = regularExpressions.size()-1; index >= 0; index--)
     72         {
     73             String regularExpression = (String)regularExpressions.get(index);
     74 
     75             StringMatcher entryMatcher = parseEntry(regularExpression);
     76 
     77             // Prepend the entry matcher.
     78             listMatcher =
     79                 listMatcher == null ?
     80                     (StringMatcher)entryMatcher :
     81                 isNegated(regularExpression) ?
     82                     (StringMatcher)new AndMatcher(entryMatcher, listMatcher) :
     83                     (StringMatcher)new OrMatcher(entryMatcher, listMatcher);
     84         }
     85 
     86         return listMatcher != null ? listMatcher : new ConstantMatcher(true);
     87     }
     88 
     89 
     90     // Small utility methods.
     91 
     92     /**
     93      * Creates a StringMatcher for the given regular expression, which is a
     94      * an optionally negated simple expression.
     95      */
     96     private StringMatcher parseEntry(String regularExpression)
     97     {
     98         // Wrap the matcher if the regular expression starts with a '!' negator.
     99         return isNegated(regularExpression) ?
    100           new NotMatcher(stringParser.parse(regularExpression.substring(1))) :
    101           stringParser.parse(regularExpression);
    102     }
    103 
    104 
    105     /**
    106      * Returns whether the given simple regular expression is negated.
    107      */
    108     private boolean isNegated(String regularExpression)
    109     {
    110         return regularExpression.length() > 0 &&
    111                regularExpression.charAt(0) == '!';
    112     }
    113 
    114 
    115     /**
    116      * A main method for testing name matching.
    117      */
    118     public static void main(String[] args)
    119     {
    120         try
    121         {
    122             System.out.println("Regular expression ["+args[0]+"]");
    123             ListParser parser  = new ListParser(new NameParser());
    124             StringMatcher  matcher = parser.parse(args[0]);
    125             for (int index = 1; index < args.length; index++)
    126             {
    127                 String string = args[index];
    128                 System.out.print("String             ["+string+"]");
    129                 System.out.println(" -> match = "+matcher.matches(args[index]));
    130             }
    131         }
    132         catch (Exception ex)
    133         {
    134             ex.printStackTrace();
    135         }
    136     }
    137 }
    138