java/ant/src/org/apidesign/infra/ant/GrepFilter.java
author Jaroslav Tulach <jtulach@netbeans.org>
Sun, 06 Jul 2008 00:12:56 +0200
changeset 268 fb9bf90251e3
child 274 e1a7420cea38
permissions -rw-r--r--
Tool to generate code snippets from sources
jtulach@268
     1
package org.apidesign.infra.ant;
jtulach@268
     2
jtulach@268
     3
import java.io.BufferedReader;
jtulach@268
     4
import java.io.File;
jtulach@268
     5
import java.io.FileReader;
jtulach@268
     6
import java.io.IOException;
jtulach@268
     7
import java.util.HashMap;
jtulach@268
     8
import java.util.Map;
jtulach@268
     9
import java.util.Stack;
jtulach@268
    10
import java.util.regex.Matcher;
jtulach@268
    11
import java.util.regex.Pattern;
jtulach@268
    12
import org.apache.tools.ant.BuildException;
jtulach@268
    13
import org.apache.tools.ant.DirectoryScanner;
jtulach@268
    14
import org.apache.tools.ant.Task;
jtulach@268
    15
import org.apache.tools.ant.types.FileSet;
jtulach@268
    16
import org.apache.tools.ant.types.FilterSet;
jtulach@268
    17
jtulach@268
    18
/**
jtulach@268
    19
 *
jtulach@268
    20
 * @author Jaroslav Tulach
jtulach@268
    21
 */
jtulach@268
    22
public final class GrepFilter extends Task {
jtulach@268
    23
    private int len = 80;
jtulach@268
    24
    private String id;
jtulach@268
    25
    private FileSet fs;
jtulach@268
    26
    private Pattern begin = Pattern.compile(".* BEGIN: *(\\p{Graph}+)[-\\> ]*");
jtulach@268
    27
    private Pattern end = Pattern.compile(".* (END|FINISH): *(\\p{Graph}+)[-\\> ]*");
jtulach@268
    28
    private boolean openoffice;
jtulach@268
    29
    
jtulach@268
    30
    
jtulach@268
    31
    public FileSet createFileSet() {
jtulach@268
    32
        if (fs != null) {
jtulach@268
    33
            throw new BuildException();
jtulach@268
    34
        }
jtulach@268
    35
        this.fs = new FileSet();
jtulach@268
    36
        return fs;
jtulach@268
    37
    }
jtulach@268
    38
    
jtulach@268
    39
    public void setId(String id) {
jtulach@268
    40
        this.id = id;
jtulach@268
    41
    }
jtulach@268
    42
    
jtulach@268
    43
    public void setMaxLineLength(int len) {
jtulach@268
    44
        this.len = len;
jtulach@268
    45
    }
jtulach@268
    46
    
jtulach@268
    47
    public void setOutputFormat(String f) {
jtulach@268
    48
        if (f.equals("opendocument")) {
jtulach@268
    49
            openoffice = true;
jtulach@268
    50
            return;
jtulach@268
    51
        }
jtulach@268
    52
        throw new BuildException("Wrong format: " + f);
jtulach@268
    53
    }
jtulach@268
    54
jtulach@268
    55
    final FilterSet createFilterSet() {
jtulach@268
    56
        if (fs == null) {
jtulach@268
    57
            throw new BuildException();
jtulach@268
    58
        }
jtulach@268
    59
        
jtulach@268
    60
        FilterSet filter = new FilterSet();
jtulach@268
    61
jtulach@268
    62
        try {
jtulach@268
    63
            DirectoryScanner ds = fs.getDirectoryScanner(getProject());
jtulach@268
    64
            Map<String,CharSequence> texts = new HashMap<String, CharSequence>();
jtulach@268
    65
            for (String path : ds.getIncludedFiles()) {
jtulach@268
    66
                File file = new File(ds.getBasedir(), path);
jtulach@268
    67
                BufferedReader r = new BufferedReader(new FileReader(file));
jtulach@268
    68
                for (;;) {
jtulach@268
    69
                    String line = r.readLine();
jtulach@268
    70
                    if (line == null) {
jtulach@268
    71
                        break;
jtulach@268
    72
                    }
jtulach@268
    73
                    {
jtulach@268
    74
                        Matcher m = begin.matcher(line);
jtulach@268
    75
                        if (m.matches()) {
jtulach@268
    76
                            Item sb = new Item(file);
jtulach@268
    77
                            CharSequence prev = texts.put(m.group(1), sb);
jtulach@268
    78
                            if (prev != null) {
jtulach@268
    79
                                throw new BuildException("Same pattern is there twice: " + m.group(1) + " in " + file);
jtulach@268
    80
                            }
jtulach@268
    81
                            continue;
jtulach@268
    82
                        }
jtulach@268
    83
                    }
jtulach@268
    84
                    {
jtulach@268
    85
                        Matcher m = end.matcher(line);
jtulach@268
    86
                        if (m.matches()) {
jtulach@268
    87
                            CharSequence s = texts.get(m.group(2));
jtulach@268
    88
                            if (s instanceof Item) {
jtulach@268
    89
                                texts.put(m.group(2), ((Item)s).toString(m.group(1).equals("FINISH")));
jtulach@268
    90
                                continue;
jtulach@268
    91
                            }
jtulach@268
    92
                            
jtulach@268
    93
                            if (s == null) {
jtulach@268
    94
                                throw new BuildException("Closing unknown section: " + m.group(2) + " in " + file);
jtulach@268
    95
                            }
jtulach@268
    96
                            throw new BuildException("Closing not opened section: " + m.group(2) + " in " + file);
jtulach@268
    97
                        }
jtulach@268
    98
                    }
jtulach@268
    99
                    
jtulach@268
   100
                    for (CharSequence charSequence : texts.values()) {
jtulach@268
   101
                        if (charSequence instanceof Item) {
jtulach@268
   102
                            Item sb = (Item)charSequence;
jtulach@268
   103
                            sb.append(line);
jtulach@268
   104
                        }
jtulach@268
   105
                    }
jtulach@268
   106
                }
jtulach@268
   107
 
jtulach@268
   108
                for (Map.Entry<String, CharSequence> entry : texts.entrySet()) {
jtulach@268
   109
                    CharSequence v = entry.getValue();
jtulach@268
   110
                    if (v instanceof Item) {
jtulach@268
   111
                        throw new BuildException("Not closed section " + entry.getKey() + " in " + file);
jtulach@268
   112
                    }
jtulach@268
   113
                    entry.setValue(v.toString());
jtulach@268
   114
                }
jtulach@268
   115
            }
jtulach@268
   116
            
jtulach@268
   117
            for (Map.Entry<String, CharSequence> entry : texts.entrySet()) {
jtulach@268
   118
                String text = entry.getValue().toString();
jtulach@268
   119
                String out = linize(text);
jtulach@268
   120
                filter.addFilter(entry.getKey(), out); // NOI18N
jtulach@268
   121
            }
jtulach@268
   122
        } catch (IOException ex) {
jtulach@268
   123
            throw new BuildException(ex);
jtulach@268
   124
        }
jtulach@268
   125
        if (!filter.hasFilters()) {
jtulach@268
   126
            throw new BuildException("No filter found!");
jtulach@268
   127
        }
jtulach@268
   128
        return filter;
jtulach@268
   129
    }
jtulach@268
   130
jtulach@268
   131
    @Override
jtulach@268
   132
    public void execute() throws BuildException {
jtulach@268
   133
        if (id == null) {
jtulach@268
   134
            throw new BuildException();
jtulach@268
   135
        }
jtulach@268
   136
        FilterSet filter = createFilterSet();
jtulach@268
   137
        getProject().addReference(id, filter);
jtulach@268
   138
    }
jtulach@268
   139
    
jtulach@268
   140
    private String linize(String input) {
jtulach@268
   141
        if (!openoffice) {
jtulach@268
   142
            return input;
jtulach@268
   143
        }
jtulach@268
   144
        
jtulach@268
   145
        StringBuilder copy = new StringBuilder();
jtulach@268
   146
        for (String l : input.split("\n")) {
jtulach@268
   147
            int spaces = 0;
jtulach@268
   148
            while (spaces < l.length() && l.charAt(spaces) == ' ') {
jtulach@268
   149
                spaces++;
jtulach@268
   150
            }
jtulach@268
   151
            copy.append("<text:p text:style-name='Code'><text:s text:c='" + spaces + "'/>" + l.substring(spaces) + "</text:p>\n");
jtulach@268
   152
        }
jtulach@268
   153
        
jtulach@268
   154
        return copy.toString();
jtulach@268
   155
    }
jtulach@268
   156
    
jtulach@268
   157
    static final int countChar(CharSequence seq, char ch) {
jtulach@268
   158
        int cnt = 0;
jtulach@268
   159
        for (int i = 0; i < seq.length(); i++) {
jtulach@268
   160
            if (ch == seq.charAt(i)) {
jtulach@268
   161
                cnt++;
jtulach@268
   162
            }
jtulach@268
   163
        }
jtulach@268
   164
        return cnt;
jtulach@268
   165
    }
jtulach@268
   166
jtulach@268
   167
    private final class Item implements CharSequence {
jtulach@268
   168
        private StringBuilder sb = new StringBuilder();
jtulach@268
   169
        private int spaces = Integer.MAX_VALUE;
jtulach@268
   170
        private Stack<Integer> remove = new Stack<Integer>();
jtulach@268
   171
        private final File file;
jtulach@268
   172
jtulach@268
   173
        public Item(File file) {
jtulach@268
   174
            this.file = file;
jtulach@268
   175
        }
jtulach@268
   176
jtulach@268
   177
        public int length() {
jtulach@268
   178
            return sb.length();
jtulach@268
   179
        }
jtulach@268
   180
jtulach@268
   181
        public char charAt(int index) {
jtulach@268
   182
            return sb.charAt(index);
jtulach@268
   183
        }
jtulach@268
   184
jtulach@268
   185
        public CharSequence subSequence(int start, int end) {
jtulach@268
   186
            return sb.subSequence(start, end);
jtulach@268
   187
        }
jtulach@268
   188
jtulach@268
   189
        private void append(String line) {
jtulach@268
   190
            for (int sp = 0; sp < line.length(); sp++) {
jtulach@268
   191
                if (line.charAt(sp) != ' ') {
jtulach@268
   192
                    if (sp < spaces) {
jtulach@268
   193
                        spaces = sp;
jtulach@268
   194
                        break;
jtulach@268
   195
                    }
jtulach@268
   196
                }
jtulach@268
   197
            }
jtulach@268
   198
            remove.push(sb.length());
jtulach@268
   199
            sb.append(line);
jtulach@268
   200
            sb.append('\n');
jtulach@268
   201
        }
jtulach@268
   202
jtulach@268
   203
        @Override
jtulach@268
   204
        public String toString() {
jtulach@268
   205
            return toString(false);
jtulach@268
   206
        }
jtulach@268
   207
        public String toString(boolean finish) {
jtulach@268
   208
            if (remove != null) {
jtulach@268
   209
                while (!remove.isEmpty()) {
jtulach@268
   210
                   Integer pos = remove.pop();
jtulach@268
   211
                   for (int i = 0; i < spaces; i++) {
jtulach@268
   212
                       if (sb.charAt(pos) == '\n') {
jtulach@268
   213
                           break;
jtulach@268
   214
                       }
jtulach@268
   215
                       sb.deleteCharAt(pos);
jtulach@268
   216
                   }
jtulach@268
   217
                }
jtulach@268
   218
                remove = null;
jtulach@268
   219
                
jtulach@268
   220
                int line = 0;
jtulach@268
   221
                for (int i = 0; i < sb.length(); i++) {
jtulach@268
   222
                    if (sb.charAt(i) == '\n') {
jtulach@268
   223
                        line = 0;
jtulach@268
   224
                        continue;
jtulach@268
   225
                    }
jtulach@268
   226
                    if (++line > len) {
jtulach@268
   227
                        throw new BuildException("Line is too long in: " + file + "\n" + sb);
jtulach@268
   228
                    }
jtulach@268
   229
                }
jtulach@268
   230
                
jtulach@268
   231
                int open = countChar(sb, '{');
jtulach@268
   232
                int end = countChar(sb, '}');
jtulach@268
   233
                if (finish) {
jtulach@268
   234
                    for (int i = 0; i < open - end; i++) {
jtulach@268
   235
                        sb.append("}\n");
jtulach@268
   236
                    }
jtulach@268
   237
                }
jtulach@268
   238
                
jtulach@268
   239
                if (countChar(sb, '{') != countChar(sb, '}')) {
jtulach@268
   240
                    throw new BuildException("not paired amount of braces in " + file + "\n" + sb);
jtulach@268
   241
                }
jtulach@268
   242
                
jtulach@268
   243
            }
jtulach@268
   244
            return sb.toString();
jtulach@268
   245
        }
jtulach@268
   246
    } // end of Item
jtulach@268
   247
}