001/*
002 * Anarres C Preprocessor
003 * Copyright (c) 2007-2015, Shevek
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
014 * or implied.  See the License for the specific language governing
015 * permissions and limitations under the License.
016 */
017package org.anarres.cpp;
018
019import java.io.File;
020import java.io.FileWriter;
021import java.io.IOException;
022import java.util.ArrayList;
023import java.util.Arrays;
024import java.util.Enumeration;
025import java.util.List;
026import org.apache.tools.ant.BuildException;
027import org.apache.tools.ant.taskdefs.Copy;
028import org.apache.tools.ant.types.Path;
029
030/**
031 * An ant task for jcpp.
032 */
033public class CppTask extends Copy {
034
035    private class Listener extends DefaultPreprocessorListener {
036
037        @Override
038        protected void print(String msg) {
039            log(msg);
040        }
041    }
042
043    public static class Macro {
044
045        private String name;
046        private String value;
047
048        public void setName(String name) {
049            this.name = name;
050        }
051
052        public String getName() {
053            return name;
054        }
055
056        public void setValue(String value) {
057            this.value = value;
058        }
059
060        public String getValue() {
061            return value;
062        }
063    }
064
065    private final Listener listener = new Listener();
066    private final List<Macro> macros = new ArrayList<Macro>();
067    private Path systemincludepath;
068    private Path localincludepath;
069
070    public void addMacro(Macro macro) {
071        macros.add(macro);
072    }
073
074    public void addSystemincludepath(Path path) {
075        if (systemincludepath == null)
076            systemincludepath = new Path(getProject());
077        systemincludepath.add(path);
078    }
079
080    public void addLocalincludepath(Path path) {
081        if (localincludepath == null)
082            localincludepath = new Path(getProject());
083        localincludepath.add(path);
084    }
085
086    /*
087     public void execute() {
088     FileWriter writer = null;
089     try {
090     if (input == null)
091     throw new BuildException("Input not specified");
092     if (output == null)
093     throw new BuildException("Output not specified");
094     cpp.addInput(this.input);
095     writer = new FileWriter(this.output);
096     for (;;) {
097     Token      tok = cpp.token();
098     if (tok != null && tok.getType() == Token.EOF)
099     break;
100     writer.write(tok.getText());
101     }
102     }
103     catch (Exception e) {
104     throw new BuildException(e);
105     }
106     finally {
107     if (writer != null) {
108     try {
109     writer.close();
110     }
111     catch (IOException e) {
112     }
113     }
114     }
115     }
116     */
117    private void preprocess(File input, File output) throws Exception {
118        if (input == null)
119            throw new BuildException("Input not specified");
120        if (output == null)
121            throw new BuildException("Output not specified");
122
123        Preprocessor cpp = new Preprocessor();
124        cpp.setListener(listener);
125        for (Macro macro : macros)
126            cpp.addMacro(macro.getName(), macro.getValue());
127        if (systemincludepath != null)
128            cpp.setSystemIncludePath(Arrays.asList(systemincludepath.list()));
129        if (localincludepath != null)
130            cpp.setQuoteIncludePath(Arrays.asList(localincludepath.list()));
131
132        File dir = output.getParentFile();
133        if (!dir.exists()) {
134            if (!dir.mkdirs())
135                throw new BuildException("Failed to make parent directory " + dir);
136        } else if (!dir.isDirectory()) {
137            throw new BuildException("Parent directory of output file " + output + " exists, but is not a directory.");
138        }
139        FileWriter writer = null;
140        try {
141            cpp.addInput(input);
142            writer = new FileWriter(output);
143            for (;;) {
144                Token tok = cpp.token();
145                if (tok == null)
146                    break;
147                if (tok.getType() == Token.EOF)
148                    break;
149                writer.write(tok.getText());
150            }
151        } finally {
152            if (writer != null) {
153                try {
154                    writer.close();
155                } catch (IOException e) {
156                }
157            }
158        }
159    }
160
161    @Override
162    protected void doFileOperations() {
163        if (fileCopyMap.size() > 0) {
164            log("Copying " + fileCopyMap.size()
165                    + " file" + (fileCopyMap.size() == 1 ? "" : "s")
166                    + " to " + destDir.getAbsolutePath());
167
168            Enumeration<String> e = fileCopyMap.keys();
169
170            while (e.hasMoreElements()) {
171                String fromFile = e.nextElement();
172                String[] toFiles = (String[]) fileCopyMap.get(fromFile);
173
174                for (String toFile : toFiles) {
175                    if (fromFile.equals(toFile)) {
176                        log("Skipping self-copy of " + fromFile, verbosity);
177                        continue;
178                    }
179
180                    try {
181                        log("Copying " + fromFile + " to " + toFile, verbosity);
182
183                        /*
184                         FilterSetCollection executionFilters
185                         = new FilterSetCollection();
186                         if (filtering) {
187                         executionFilters
188                         .addFilterSet(getProject().getGlobalFilterSet());
189                         }
190                         for (Enumeration filterEnum = getFilterSets().elements();
191                         filterEnum.hasMoreElements();) {
192                         executionFilters
193                         .addFilterSet((FilterSet) filterEnum.nextElement());
194                         }
195                         */
196                        File srcFile = new File(fromFile);
197                        File dstFile = new File(toFile);
198                        preprocess(srcFile, dstFile);
199                    } catch (Exception ioe) {
200                        // ioe.printStackTrace();
201                        String msg = "Failed to copy " + fromFile + " to " + toFile
202                                + " due to " + ioe.getMessage();
203                        File targetFile = new File(toFile);
204                        if (targetFile.exists() && !targetFile.delete()) {
205                            msg += " and I couldn't delete the corrupt " + toFile;
206                        }
207                        throw new BuildException(msg, ioe, getLocation());
208                    }
209                }
210            }
211        }
212
213    }
214
215}