001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.nbbuild;
043:
044: import java.io.*;
045: import java.util.*;
046:
047: import org.apache.tools.ant.*;
048: import org.apache.tools.ant.taskdefs.MatchingTask;
049:
050: // In Javadoc below: * == *
051: /** Preprocesses content of file replacing all conditional blocks.
052: * <PRE>
053: * /*nbif someswitch
054: * // PART A
055: * nbelse*/
056: * // PART B
057: * /*nbend*/
058: * </PRE>
059: * If <code>someswitch</code> is off, nothing will be changed, so part A will be
060: * commented-out and part B will be active. If <code>someswitch</code> is on,
061: * the code will be changed to:
062: * <PRE>
063: * /*nbif someswitch*/
064: * // PART A
065: * /*nbelse
066: * // PART B
067: * /*nbend*/
068: * </PRE>
069: * So that part A is active and part B is commented-out.
070: * <p>You can also use a block without an else:
071: * <PRE>
072: * /*nbif someswitch
073: * // PART A
074: * /*nbend*/
075: * </PRE>
076: * With the switch off, it will again be left as is, i.e. commented-out. With the switch
077: * on, you will get:
078: * <PRE>
079: * /*nbif someswitch*/
080: * // PART A
081: * /*nbend*/
082: * </PRE>
083: * where the interior section is now active.
084: * <p>Intent of this preprocessor is to permit incompatible API changes to made in source
085: * code, while creating a variant binary compatibility kit without the changes or with
086: * more conservative changes. It should <em>not</em> be used as a general-purpose Java
087: * preprocessor, we are not C++ programmers here!
088: * @author Jaroslav Tulach, Jesse Glick
089: * @deprecated No longer used.
090: */
091: @Deprecated
092: public class Preprocess extends MatchingTask {
093: /** the format of begining of substitution */
094: private static final String F_BEGIN = "/*nbif"; // NOI18N
095: /** format of else statement */
096: private static final String F_ELSE = "nbelse*/"; // NOI18N
097: /** how to replace the else */
098: private static final String R_ELSE = "/*nbelse"; // NOI18N
099: /** format of end statement */
100: private static final String F_END = "/*nbend*/"; // NOI18N
101:
102: /** source directory to scan files from */
103: private File src;
104: /** target directory */
105: private File dest;
106: /** copy all/copy modified */
107: private boolean copyAll = false;
108: /** switches to check in conditionals */
109: private List<Switch> switches = new LinkedList<Switch>();
110:
111: /** Setter for the source directory to scan. */
112: public void setSrcDir(File f) {
113: src = f;
114: }
115:
116: /** Setter for the target directory to create processed files in.
117: */
118: public void setDestDir(File f) {
119: dest = f;
120: }
121:
122: /** Can be set to copy all files, if necessary.
123: * Default is not to copy a file unless it was actually modified.
124: * @param copyAll true if all files (even unmodified) should be copied
125: */
126: public void setCopyAll(boolean copyAll) {
127: this .copyAll = copyAll;
128: }
129:
130: /** A switch to use as the test in preprocessor conditionals.
131: * Only switches explicitly listed here will be recognized.
132: */
133: public class Switch {
134: String name;
135: boolean on;
136:
137: /** Set the name of the switch, which will be used in <code>nbif</code> tests. */
138: public void setName(String name) {
139: this .name = name;
140: }
141:
142: /** Set whether the switch should be on or not. */
143: public void setOn(boolean on) {
144: this .on = on;
145: }
146: }
147:
148: /** Add a conditional switch to control preprocessing. */
149: public Switch createSwitch() {
150: Switch s = new Switch();
151: switches.add(s);
152: return s;
153: }
154:
155: public void execute() throws BuildException {
156: if (src == null || dest == null) {
157: throw new BuildException("src and dest must be specified");
158: }
159: if (switches.isEmpty()) {
160: throw new BuildException(
161: "Useless to preprocess sources with no switches specified!");
162: }
163:
164: DirectoryScanner scanner = getDirectoryScanner(src);
165: scanner.scan();
166: String[] files = scanner.getIncludedFiles();
167: String message1 = "Processing " + files.length
168: + " file(s) from directory " + src + " to " + dest;
169:
170: StringBuffer message2 = new StringBuffer("Switches:");
171: Set<String> ss = new HashSet<String>();
172: for (Switch s : switches) {
173: if (s.on) {
174: ss.add(s.name);
175: message2.append(' ');
176: message2.append(s.name);
177: } else {
178: message2.append(" !");
179: message2.append(s.name);
180: }
181: }
182:
183: try {
184: boolean shownMessages = false;
185: for (int i = 0; i < files.length; i++) {
186: File src = new File(this .src, files[i]);
187: File dest = new File(this .dest, files[i]);
188: // Up-to-date check (note that this ignores changes in
189: // switches; for that you must clean first!):
190: if (dest.exists()
191: && dest.lastModified() >= src.lastModified()) {
192: continue;
193: }
194:
195: int size = (int) src.length() + 500;
196: BufferedReader r = new BufferedReader(new FileReader(
197: src), size);
198: StringWriter w = new StringWriter(size);
199:
200: boolean modified = replace(r, w, ss);
201: w.close();
202: r.close();
203:
204: if ((modified || copyAll) && !shownMessages) {
205: shownMessages = true;
206: log(message1);
207: log(message2.toString());
208: }
209:
210: if (modified) {
211: log("Modified: " + files[i]);
212: }
213:
214: if (modified || copyAll) {
215: // the file has been modified
216:
217: // ensure the directories exists
218: File dir = dest.getParentFile();
219: dir.mkdirs();
220:
221: Writer file = new FileWriter(dest);
222: file.write(w.getBuffer().toString());
223: file.close();
224: }
225: }
226: } catch (IOException ex) {
227: throw new BuildException(ex);
228: }
229: }
230:
231: /*nbif test
232: public static void main (String[] args) throws IOException {
233: BufferedReader r = new BufferedReader (
234: new FileReader (args[0])
235: );
236:
237: BufferedWriter w = new BufferedWriter (
238: new OutputStreamWriter (System.out), System.getProperties ()
239: );
240:
241: replace (r, w);
242:
243: w.close ();
244: }
245: /*nbend*/
246:
247: /** Reads a content of a file and produces replaces given lines
248: *
249: * @param r reader to read from
250: * @param w writer to write to
251: * @param props properties to be considered on
252: * @return true if the content of r has been modified
253: */
254: @SuppressWarnings("fallthrough")
255: private static boolean replace(BufferedReader r, Writer w, Set props // Set<String>
256: ) throws IOException {
257: boolean modified = false;
258:
259: int state = 0;
260:
261: for (;;) {
262: String line = r.readLine();
263: if (line == null) {
264: return modified;
265: }
266:
267: switch (state) {
268: case 0: // regular text
269: if (line.trim().startsWith(F_BEGIN)) {
270: String rest = line.trim().substring(
271: F_BEGIN.length()).trim();
272: if (props.contains(rest)) {
273: // successful test, the content of line should
274: // be included
275: line += "*/"; // NOI18N
276: modified = true;
277: state = 1;
278: }
279: }
280: break;
281: case 1: // waiting for the nbelse*/ statement
282: if (line.trim().equals(F_ELSE)) {
283: line = R_ELSE;
284: modified = true; // redundant, for clarity
285: state = 2;
286: }
287: // FALLTHROUGH: OK to have a if-end block with no else!
288: case 2: // inside the else, waiting for end
289: if (line.trim().equals(F_END)) {
290: state = 0;
291: }
292: break;
293: }
294:
295: w.write(line);
296: w.write('\n');
297: }
298: }
299: }
|