Source code: org/hsqldb/util/CodeSwitcher.java
1 /* Copyrights and Licenses
2 *
3 * This product includes Hypersonic SQL.
4 * Originally developed by Thomas Mueller and the Hypersonic SQL Group.
5 *
6 * Copyright (c) 1995-2000 by the Hypersonic SQL Group. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without modification, are permitted
8 * provided that the following conditions are met:
9 * - Redistributions of source code must retain the above copyright notice, this list of conditions
10 * and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright notice, this list of
12 * conditions and the following disclaimer in the documentation and/or other materials
13 * provided with the distribution.
14 * - All advertising materials mentioning features or use of this software must display the
15 * following acknowledgment: "This product includes Hypersonic SQL."
16 * - Products derived from this software may not be called "Hypersonic SQL" nor may
17 * "Hypersonic SQL" appear in their names without prior written permission of the
18 * Hypersonic SQL Group.
19 * - Redistributions of any form whatsoever must retain the following acknowledgment: "This
20 * product includes Hypersonic SQL."
21 * This software is provided "as is" and any expressed or implied warranties, including, but
22 * not limited to, the implied warranties of merchantability and fitness for a particular purpose are
23 * disclaimed. In no event shall the Hypersonic SQL Group or its contributors be liable for any
24 * direct, indirect, incidental, special, exemplary, or consequential damages (including, but
25 * not limited to, procurement of substitute goods or services; loss of use, data, or profits;
26 * or business interruption). However caused any on any theory of liability, whether in contract,
27 * strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this
28 * software, even if advised of the possibility of such damage.
29 * This software consists of voluntary contributions made by many individuals on behalf of the
30 * Hypersonic SQL Group.
31 *
32 *
33 * For work added by the HSQL Development Group:
34 *
35 * Copyright (c) 2001-2002, The HSQL Development Group
36 * All rights reserved.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions are met:
40 *
41 * Redistributions of source code must retain the above copyright notice, this
42 * list of conditions and the following disclaimer, including earlier
43 * license statements (above) and comply with all above license conditions.
44 *
45 * Redistributions in binary form must reproduce the above copyright notice,
46 * this list of conditions and the following disclaimer in the documentation
47 * and/or other materials provided with the distribution, including earlier
48 * license statements (above) and comply with all above license conditions.
49 *
50 * Neither the name of the HSQL Development Group nor the names of its
51 * contributors may be used to endorse or promote products derived from this
52 * software without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
55 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
58 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
59 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
60 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
61 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
62 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
63 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
64 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
65 */
66
67
68 package org.hsqldb.util;
69
70 import java.io.*;
71 import java.util.*;
72
73 // fredt@users 20020315 - patch 1.7.0 - minor fixes
74 // changed line separator to System based value
75 // moved the Profile class to org.hsqldb.test package
76 // fredt@users 20021020 - patch 1.7.1 - formatting fix
77 // avoid moving blank lines which would be interpreted as code change by CVS
78
79 /**
80 * Modifies the source code to support different JDK or profile settings. <p>
81 * <pre>
82 * Usage: java CodeSwitcher [paths] [labels] [+][-]
83 * If no labels are specified then all used
84 * labels in the source code are shown.
85 * Use +MODE to switch on the things labeld MODE
86 * Use -MODE to switch off the things labeld MODE
87 * Path: Any number of path or files may be
88 * specified. Use . for the current directory
89 * (including sub-directories).
90 * Example: java CodeSwitcher +JAVA2 .
91 * This example switches on code labeled JAVA2
92 * in all *.java files in the current directory
93 * and all subdirectories.
94 * java CodeSwitcher + .
95 * Adds test code to the code.
96 * java CodeSwitcher - .
97 * Removes test code from the code
98 * </pre>
99 *
100 * @version 1.7.0
101 */
102 public class CodeSwitcher {
103
104 private static final String ls = System.getProperty("line.separator",
105 "\n");
106 private Vector vList;
107 private Vector vSwitchOn;
108 private Vector vSwitchOff;
109 private Vector vSwitches;
110 private boolean bAdd, bRemove;
111 private static final int MAX_LINELENGTH = 82;
112
113 /**
114 * Method declaration
115 *
116 *
117 * @param a
118 */
119 public static void main(String a[]) {
120
121 CodeSwitcher s = new CodeSwitcher();
122
123 if (a.length == 0) {
124 showUsage();
125
126 return;
127 }
128
129 boolean path = false;
130
131 for (int i = 0; i < a.length; i++) {
132 String p = a[i];
133
134 if (p.startsWith("+")) {
135 if (p.length() == 1) {
136 s.bAdd = true;
137 } else {
138 s.vSwitchOn.addElement(p.substring(1));
139 }
140 } else if (p.startsWith("-")) {
141 if (p.length() == 1) {
142 s.bRemove = true;
143 } else {
144 s.vSwitchOff.addElement(p.substring(1));
145 }
146 } else {
147 s.addDir(p);
148
149 path = true;
150 }
151 }
152
153 if (!path) {
154 printError("no path specified");
155 showUsage();
156 }
157
158 s.process();
159
160 if (s.vSwitchOff.size() == 0 && s.vSwitchOn.size() == 0) {
161 s.printSwitches();
162 }
163 }
164
165 /**
166 * Method declaration
167 *
168 */
169 static void showUsage() {
170
171 System.out.print("Usage: java CodeSwitcher [paths] [labels] [+][-]\n"
172 + "If no labels are specified then all used\n"
173 + "labels in the source code are shown.\n"
174 + "Use +MODE to switch on the things labeld MODE\n"
175 + "Use -MODE to switch off the things labeld MODE\n"
176 + "Path: Any number of path or files may be\n"
177 + "specified. Use . for the current directory\n"
178 + "(including sub-directories).\n"
179 + "Example: java CodeSwitcher +JAVA2 .\n"
180 + "This example switches on code labeled JAVA2\n"
181 + "in all *.java files in the current directory\n"
182 + "and all subdirectories.\n"
183 + "java CodeSwitcher + .\n"
184 + "Adds test code to the code.\n"
185 + "java CodeSwitcher - .\n"
186 + "Removed test code from the code.\n");
187 }
188
189 /**
190 * Constructor declaration
191 *
192 */
193 CodeSwitcher() {
194
195 vList = new Vector();
196 vSwitchOn = new Vector();
197 vSwitchOff = new Vector();
198 vSwitches = new Vector();
199 }
200
201 /**
202 * Method declaration
203 *
204 */
205 void process() {
206
207 int len = vList.size();
208
209 for (int i = 0; i < len; i++) {
210 System.out.print(".");
211
212 String file = (String) vList.elementAt(i);
213
214 if (bAdd || bRemove) {
215 int maxlen = testFile(file);
216
217 if (bAdd &&!bRemove) {
218 addTest(file, maxlen);
219 } else {
220 removeTest(file);
221 }
222 } else {
223 if (!processFile(file)) {
224 System.out.println("in file " + file + " !");
225 }
226 }
227 }
228
229 System.out.println("");
230 }
231
232 /**
233 * Method declaration
234 *
235 */
236 void printSwitches() {
237
238 System.out.println("Used labels:");
239
240 for (int i = 0; i < vSwitches.size(); i++) {
241 System.out.println((String) (vSwitches.elementAt(i)));
242 }
243 }
244
245 /**
246 * Method declaration
247 *
248 *
249 * @param path
250 */
251 void addDir(String path) {
252
253 File f = new File(path);
254
255 if (f.isFile() && path.endsWith(".java")) {
256 vList.addElement(path);
257 } else if (f.isDirectory()) {
258 String list[] = f.list();
259
260 for (int i = 0; i < list.length; i++) {
261 addDir(path + File.separatorChar + list[i]);
262 }
263 }
264 }
265
266 /**
267 * Method declaration
268 *
269 *
270 * @param name
271 */
272 void removeTest(String name) {
273
274 File f = new File(name);
275 File fnew = new File(name + ".new");
276
277 try {
278 LineNumberReader read = new LineNumberReader(new FileReader(f));
279 FileWriter write = new FileWriter(fnew);
280
281 while (true) {
282 String line = read.readLine();
283
284 if (line == null) {
285 break;
286 }
287
288 if (line.startsWith("Profile.visit(")) {
289 int s = line.indexOf(';');
290
291 line = line.substring(s + 1);
292 }
293
294 write.write(line + ls);
295 }
296
297 read.close();
298 write.flush();
299 write.close();
300
301 File fbak = new File(name + ".bak");
302
303 fbak.delete();
304 f.renameTo(fbak);
305
306 File fcopy = new File(name);
307
308 fnew.renameTo(fcopy);
309 fbak.delete();
310 } catch (Exception e) {
311 printError(e.getMessage());
312 }
313 }
314
315 /**
316 * Method declaration
317 *
318 *
319 * @param name
320 * @param maxline
321 */
322 void addTest(String name, int maxline) {
323
324 File f = new File(name);
325 File fnew = new File(name + ".new");
326 String key = name;
327
328 key = key.replace('\\', '.');
329
330 try {
331 LineNumberReader read = new LineNumberReader(new FileReader(f));
332 FileWriter write = new FileWriter(fnew);
333 int l = 0;
334 boolean longline = false;
335
336 while (true) {
337 String line = read.readLine();
338
339 if (line == null) {
340 break;
341 }
342
343 if (line.startsWith(" ")) {
344 int spaces = 0;
345
346 for (; spaces < line.length(); spaces++) {
347 if (line.charAt(spaces) != ' ') {
348 break;
349 }
350 }
351
352 if (spaces > 3 && testLine(line) &&!longline) {
353 line = "org.hsqldb.test.Profile.visit(\"" + key
354 + "\"," + l + "," + maxline + ");" + line;
355
356 l++;
357 } else if (isLongline(line)) {
358 longline = true;
359 } else {
360 longline = false;
361 }
362 }
363
364 write.write(line + ls);
365 }
366
367 read.close();
368 write.flush();
369 write.close();
370
371 File fbak = new File(name + ".bak");
372
373 fbak.delete();
374 f.renameTo(fbak);
375
376 File fcopy = new File(name);
377
378 fnew.renameTo(fcopy);
379 fbak.delete();
380 } catch (Exception e) {
381 printError(e.getMessage());
382 }
383 }
384
385 /**
386 * Method declaration
387 *
388 *
389 * @param name
390 *
391 * @return
392 */
393 int testFile(String name) {
394
395 File f = new File(name);
396
397 try {
398 LineNumberReader read = new LineNumberReader(new FileReader(f));
399 int l = 1,
400 maxline = 0;
401 boolean longline = false;
402
403 while (true) {
404 String line = read.readLine();
405
406 if (line == null) {
407 break;
408 }
409
410 if (line.length() > MAX_LINELENGTH
411 &&!line.startsWith("org.hsqldb.test.Profile.")) {
412 System.out.println("long line in " + name + " at line "
413 + l);
414 }
415
416 if (line.startsWith(" ")) {
417 int spaces = 0;
418
419 for (; spaces < line.length(); spaces++) {
420 if (line.charAt(spaces) != ' ') {
421 break;
422 }
423 }
424
425 if (spaces > 3 && testLine(line) &&!longline) {
426 maxline++;
427 } else if (isLongline(line)) {
428 longline = true;
429 } else {
430 longline = false;
431 }
432
433 String s = line.substring(spaces);
434
435 if (s.startsWith("if(")) {
436 if (!s.endsWith(" {")) {
437 System.out.println("if( without { in " + name
438 + " at line " + l);
439 }
440 } else if (s.startsWith("} else if(")) {
441 if (!s.endsWith(" {")) {
442 System.out.println("} else if without { in "
443 + name + " at line " + l);
444 }
445 } else if (s.startsWith("while(")) {
446 if (!s.endsWith(" {")) {
447 System.out.println("while( without { in " + name
448 + " at line " + l);
449 }
450 } else if (s.startsWith("switch(")) {
451 if (!s.endsWith(" {")) {
452 System.out.println("switch( without { in " + name
453 + " at line " + l);
454 }
455 } else if (s.startsWith("do ")) {
456 if (!s.endsWith(" {")) {
457 System.out.println("do without { in " + name
458 + " at line " + l);
459 }
460 }
461 }
462
463 l++;
464 }
465
466 read.close();
467
468 return maxline;
469 } catch (Exception e) {
470 printError(e.getMessage());
471 }
472
473 return -1;
474 }
475
476 /**
477 * Method declaration
478 *
479 *
480 * @param line
481 *
482 * @return
483 */
484 boolean testLine(String line) {
485
486 if (!line.endsWith(";")) {
487 return false;
488 }
489
490 if (line.trim().startsWith("super(")) {
491 return false;
492 }
493
494 return true;
495 }
496
497 /**
498 * Method declaration
499 *
500 *
501 * @param s
502 *
503 * @return
504 */
505 boolean isLongline(String s) {
506
507 char c = s.charAt(s.length() - 1);
508
509 if (",(+-&|".indexOf(c) >= 0) {
510 return true;
511 }
512
513 return false;
514 }
515
516 /**
517 * Method declaration
518 *
519 *
520 * @param name
521 *
522 * @return
523 */
524 boolean processFile(String name) {
525
526 File f = new File(name);
527 File fnew = new File(name + ".new");
528 int state = 0; // 0=normal 1=inside_if 2=inside_else
529 boolean switchoff = false;
530 boolean working = false;
531
532 try {
533 Vector v = getFileLines(f);
534
535 for (int i = 0; i < v.size(); i++) {
536 String line = (String) v.elementAt(i);
537
538 if (line == null) {
539 break;
540 }
541
542 if (working) {
543 if (line.equals("/*") || line.equals("*/")) {
544 v.removeElementAt(i--);
545
546 continue;
547 }
548 }
549
550 if (!line.startsWith("//#")) {
551
552 } else {
553 if (line.startsWith("//#ifdef ")) {
554 if (state != 0) {
555 printError(
556 "'#ifdef' not allowed inside '#ifdef'");
557
558 return false;
559 }
560
561 state = 1;
562
563 String s = line.substring(9);
564
565 if (vSwitchOn.indexOf(s) != -1) {
566 working = true;
567 switchoff = false;
568 } else if (vSwitchOff.indexOf(s) != -1) {
569 working = true;
570
571 v.insertElementAt("/*",++i);
572
573 switchoff = true;
574 }
575
576 if (vSwitches.indexOf(s) == -1) {
577 vSwitches.addElement(s);
578 }
579 } else if (line.startsWith("//#else")) {
580 if (state != 1) {
581 printError("'#else' without '#ifdef'");
582
583 return false;
584 }
585
586 state = 2;
587
588 if (!working) {
589
590 } else if (switchoff) {
591 if (v.elementAt(i - 1).equals("")) {
592 v.insertElementAt("*/",i - 1);
593
594 i++;
595 } else {
596 v.insertElementAt( "*/",i++);
597 }
598
599 switchoff = false;
600 } else {
601
602 v.insertElementAt("/*",++i);
603
604 switchoff = true;
605 }
606 } else if (line.startsWith("//#endif")) {
607 if (state == 0) {
608 printError("'#endif' without '#ifdef'");
609
610 return false;
611 }
612
613 state = 0;
614
615 if (working && switchoff) {
616 if (v.elementAt(i - 1).equals("")) {
617 v.insertElementAt( "*/", i - 1);
618
619 i++;
620 } else {
621 v.insertElementAt("*/",i++ );
622 }
623 }
624
625 working = false;
626 } else {
627
628 }
629 }
630 }
631
632 if (state != 0) {
633 printError("'#endif' missing");
634
635 return false;
636 }
637
638 writeFileLines(v, fnew);
639
640 File fbak = new File(name + ".bak");
641
642 fbak.delete();
643 f.renameTo(fbak);
644
645 File fcopy = new File(name);
646
647 fnew.renameTo(fcopy);
648 fbak.delete();
649
650 return true;
651 } catch (Exception e) {
652 printError(e.getMessage());
653
654 return false;
655 }
656 }
657
658 static Vector getFileLines(File f) throws IOException {
659
660 LineNumberReader read = new LineNumberReader(new FileReader(f));
661 Vector v = new Vector();
662
663 for (;;) {
664 String line = read.readLine();
665
666 if (line == null) {
667 break;
668 }
669
670 v.addElement(line);
671 }
672
673 read.close();
674
675 return v;
676 }
677
678 static void writeFileLines(Vector v, File f) throws IOException {
679
680 FileWriter write = new FileWriter(f);
681
682 for (int i = 0; i < v.size(); i++) {
683 write.write((String) v.elementAt(i));
684 write.write(ls);
685 }
686
687 write.flush();
688 write.close();
689 }
690
691 /**
692 * Method declaration
693 *
694 *
695 * @param error
696 */
697 static void printError(String error) {
698 System.out.println("");
699 System.out.println("ERROR: " + error);
700 }
701 }