1 /*
2  * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  *
23  */
24 
25 import java.io.*;
26 import java.util.*;
27 
28 class jvmtiEnvFill {
29 
main(String[] args)30     public static void main(String[] args) throws IOException {
31         if (args.length != 3) {
32             System.err.println("usage: <filledFile> <stubFile> <resultFile>");
33             System.exit(1);
34         }
35         String filledFN = args[0];
36         String stubFN = args[1];
37         String resultFN = args[2];
38 
39         SourceFile filledSF = new SourceFile(filledFN);
40         SourceFile stubSF = new SourceFile(stubFN);
41 
42 
43         stubSF.fill(filledSF);
44 
45         PrintWriter out = new PrintWriter(new FileWriter(resultFN));
46         stubSF.output(out);
47         out.close();
48     }
49 }
50 
51 class SourceFile {
52 
53     static final String endFilePrefix = "// end file prefix";
54     static final String functionPrefix = "JvmtiEnv::";
55 
56     final String fn;
57     LineNumberReader in;
58     String line;
59     List<String> top = new ArrayList<String>();
60     List<String> before = new ArrayList<String>();
61     boolean inFilePrefix = true;
62     List<Function> functions = new ArrayList<Function>();
63     Map<String, Function> functionMap = new HashMap<String, Function>();
64 
65     class Function {
66       String name;
67       String args;
68       String compareArgs;
69       List comment;
70       List<String> body = new ArrayList<String>();
71 
Function()72       Function() throws IOException {
73         line = in.readLine();
74         String trimmed = line.trim();
75         if (!trimmed.startsWith(functionPrefix)) {
76             error("expected '" + functionPrefix + "'");
77         }
78         int index = trimmed.indexOf('(', functionPrefix.length());
79         if (index == -1) {
80             error("missing open paren");
81         }
82         name = trimmed.substring(functionPrefix.length(), index);
83         int index2 = trimmed.indexOf(')', index);
84         if (index2 == -1) {
85             error("missing close paren - must be on same line");
86         }
87         args = trimmed.substring(index+1, index2);
88         compareArgs = args.replaceAll("\\s", "");
89         String tail = trimmed.substring(index2+1).trim();
90         if (!tail.equals("{")) {
91             error("function declaration first line must end with open bracket '{', instead got '" +
92                    tail + "'");
93         }
94         while(true) {
95             line = in.readLine();
96             if (line == null) {
97                 line = ""; // so error does not look wierd
98                 error("unexpected end of file");
99             }
100             if (line.startsWith("}")) {
101                 break;
102             }
103             body.add(line);
104         }
105         String expected = "} /* end " + name + " */";
106         trimmed = line.replaceAll("\\s","");
107         if (!trimmed.equals(expected.replaceAll("\\s",""))) {
108             error("function end is malformed - should be: " + expected);
109         }
110         // copy over the comment prefix
111         comment = before;
112         before = new ArrayList<String>();
113       }
114 
remove()115       void remove() {
116         functionMap.remove(name);
117       }
118 
fileName()119       String fileName() {
120         return fn;
121       }
122 
fill(Function filledFunc)123       void fill(Function filledFunc) {
124         if (filledFunc == null) {
125             System.err.println("Warning: function " + name + " missing from filled file");
126             body.add(0, "    /*** warning: function added and not filled in ***/");
127         } else {
128             int fbsize = filledFunc.body.size();
129             int bsize = body.size();
130             if (fbsize > bsize  || !body.subList(bsize-fbsize,bsize).equals(filledFunc.body)) {
131                 // it has actually been filled in
132                 body = filledFunc.body;
133                 if (!compareArgs.equals(filledFunc.compareArgs)) {
134                     System.err.println("Warning: function " + name +
135                                        ": filled and stub arguments differ");
136                     System.err.println("  old (filled): " + filledFunc.args);
137                     System.err.println("  new (stub): " + args);
138                     body.add(0, "    /*** warning: arguments changed, were: " +
139                              filledFunc.args + " ***/");
140                 }
141             }
142             filledFunc.remove();  // mark used
143         }
144       }
145 
output(PrintWriter out)146       void output(PrintWriter out) {
147             Iterator it = comment.iterator();
148             while (it.hasNext()) {
149                 out.println(it.next());
150             }
151             out.println("jvmtiError");
152             out.print(functionPrefix);
153             out.print(name);
154             out.print('(');
155             out.print(args);
156             out.println(") {");
157             it = body.iterator();
158             while (it.hasNext()) {
159                 out.println(it.next());
160             }
161             out.print("} /* end ");
162             out.print(name);
163             out.println(" */");
164       }
165     }
166 
SourceFile(String fn)167     SourceFile(String fn) throws IOException {
168         this.fn = fn;
169         Reader reader = new FileReader(fn);
170         in = new LineNumberReader(reader);
171 
172         while (readGaps()) {
173             Function func = new Function();
174             functionMap.put(func.name, func);
175             functions.add(func);
176         }
177 
178         in.close();
179     }
180 
error(String msg)181     void error(String msg) {
182         System.err.println("Fatal error parsing file: " + fn);
183         System.err.println("Line number: " + in.getLineNumber());
184         System.err.println("Error message: " + msg);
185         System.err.println("Source line: " + line);
186         System.exit(1);
187     }
188 
readGaps()189     boolean readGaps() throws IOException {
190         while(true) {
191             line = in.readLine();
192             if (line == null) {
193                 return false; // end of file
194             }
195             if (!inFilePrefix && line.startsWith("}")) {
196                 error("unexpected close bracket in first column, outside of function.\n");
197             }
198             String trimmed = line.trim();
199             if (line.startsWith("jvmtiError")) {
200                 if (trimmed.equals("jvmtiError")) {
201                     if (inFilePrefix) {
202                         error("unexpected 'jvmtiError' line in file prefix.\n" +
203                               "is '" + endFilePrefix + "'... line missing?");
204                     }
205                     return true; // beginning of a function
206                 } else {
207                     error("extra characters at end of 'jvmtiError'");
208                 }
209             }
210             if (inFilePrefix) {
211                 top.add(line);
212             } else {
213                 trimmed = line.trim();
214                 if (!trimmed.equals("") && !trimmed.startsWith("//") && !trimmed.startsWith("#")) {
215                     error("only comments and blank lines allowed between functions");
216                 }
217                 before.add(line);
218             }
219             if (line.replaceAll("\\s","").toLowerCase().startsWith(endFilePrefix.replaceAll("\\s",""))) {
220                 if (!inFilePrefix) {
221                     error("excess '" + endFilePrefix + "'");
222                 }
223                 inFilePrefix = false;
224             }
225         }
226     }
227 
fill(SourceFile filledSF)228     void fill(SourceFile filledSF) {
229         // copy beginning of file straight from filled file
230         top = filledSF.top;
231 
232         // file in functions
233         Iterator it = functions.iterator();
234         while (it.hasNext()) {
235             Function stubFunc = (Function)(it.next());
236             Function filledFunc = (Function)filledSF.functionMap.get(stubFunc.name);
237             stubFunc.fill(filledFunc);
238         }
239         if (filledSF.functionMap.size() > 0) {
240             System.err.println("Warning: the following functions were present in the " +
241                                 "filled file but missing in the stub file and thus not copied:");
242             it  = filledSF.functionMap.values().iterator();
243             while (it.hasNext()) {
244                 System.err.println("        " + ((Function)(it.next())).name);
245             }
246         }
247     }
248 
output(PrintWriter out)249     void output(PrintWriter out) {
250         Iterator it = top.iterator();
251         while (it.hasNext()) {
252             out.println(it.next());
253         }
254         it = functions.iterator();
255         while (it.hasNext()) {
256             Function stubFunc = (Function)(it.next());
257             stubFunc.output(out);
258         }
259     }
260 }
261