1 package org.sonatype.plugins.munge;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.*;
23 import java.util.*;
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105 public class Munge {
106
107 static Hashtable symbols = new Hashtable(2);
108
109 static Vector oldTextStrings = new Vector();
110 static Vector newTextStrings = new Vector();
111
112 int errors = 0;
113 int line = 1;
114 String inName;
115 BufferedReader in;
116 PrintWriter out;
117 Stack stack = new Stack();
118 boolean printing = true;
119 String source = null;
120 String block = null;
121
122 final String[] commands = { "if", "if_not", "else", "end" };
123 final int IF = 0;
124 final int IF_NOT = 1;
125 final int ELSE = 2;
126 final int END = 3;
127 final int numCommands = 4;
128
129 final int EOF = 0;
130 final int COMMENT = 1;
131 final int CODE = 2;
132
133 int getCommand(String s) {
134 for (int i = 0; i < numCommands; i++) {
135 if (s.equals(commands[i])) {
136 return i;
137 }
138 }
139 return -1;
140 }
141
142 public void error(String text) {
143 System.err.println("File " + inName + " line " + line + ": " + text);
144 errors++;
145 }
146
147 public void printErrorCount() {
148 if (errors > 0) {
149 System.err.println(Integer.toString(errors) +
150 (errors > 1 ? " errors" : " error"));
151 }
152 }
153
154 public boolean hasErrors() {
155 return (errors > 0);
156 }
157
158 public Munge(String inName, String outName) {
159 this.inName = inName;
160 if( inName == null ) {
161 in = new BufferedReader( new InputStreamReader(System.in) );
162 } else {
163 try {
164 in = new BufferedReader( new FileReader(inName) );
165 } catch (FileNotFoundException fnf) {
166 System.err.println("Cannot find input file " + inName);
167 errors++;
168 return;
169 }
170 }
171
172 if( outName == null ) {
173 out = new PrintWriter(System.out);
174 } else {
175 try {
176 out = new PrintWriter( new FileWriter(outName) );
177 } catch (IOException ioe) {
178 System.err.println("Cannot write to file " + outName);
179 errors++;
180 }
181 }
182 }
183
184 public void close() throws IOException {
185 in.close();
186 out.flush();
187 out.close();
188 }
189
190 void cmd_if(String version) {
191 Boolean b = new Boolean(printing);
192 stack.push(b);
193 printing = (symbols.get(version) != null);
194 }
195
196 void cmd_if_not(String version) {
197 Boolean b = new Boolean(printing);
198 stack.push(b);
199 printing = (symbols.get(version) == null);
200 }
201
202 void cmd_else() {
203 printing = !printing;
204 }
205
206 void cmd_end() throws EmptyStackException {
207 Boolean b = (Boolean)stack.pop();
208 printing = b.booleanValue();
209 }
210
211 void print(String s) throws IOException {
212 if (printing) {
213 out.write(s);
214 } else {
215
216 int n = countLines(s);
217 for (int i = 0; i < n; i++) {
218 out.write('\n');
219 }
220 }
221 }
222
223
224 int countLines(String s) {
225 int i = 0;
226 int n = 0;
227 while ((i = block.indexOf('\n', i) + 1) > 0) {
228 n++;
229 }
230 return n;
231 }
232
233
234
235
236
237 void processComment(String comment) throws IOException {
238 String commentText = comment.substring(2, comment.length() - 2);
239 StringTokenizer st = new StringTokenizer(
240 commentText, "[] \t\r\n", true);
241 boolean foundTag = false;
242 StringBuffer buffer = new StringBuffer();
243
244 try {
245 while (st.hasMoreTokens()) {
246 String token = st.nextToken();
247 int cmd = getCommand(token);
248 if (cmd == -1) {
249 buffer.append(token);
250 if (token.equals("\n")) {
251 line++;
252 }
253 } else {
254 token = st.nextToken();
255 if (!token.equals("[")) {
256
257 buffer.append(commands[cmd]);
258 buffer.append(token);
259 } else {
260 String symbol = st.nextToken();
261 if (!st.nextToken().equals("]")) {
262 error("invalid preprocessor statement");
263 }
264 foundTag = true;
265
266
267 print(buffer.toString());
268 buffer.setLength(0);
269
270 switch (cmd) {
271 case IF:
272 cmd_if(symbol);
273 break;
274 case IF_NOT:
275 cmd_if_not(symbol);
276 break;
277 case ELSE:
278 cmd_else();
279 break;
280 case END:
281 cmd_end();
282 break;
283 default:
284 throw new InternalError("bad command");
285 }
286 }
287 }
288 }
289 } catch (NoSuchElementException nse) {
290 error("invalid preprocessor statement");
291 } catch (EmptyStackException ese) {
292 error("unmatched end or else statement");
293 }
294
295 if (foundTag) {
296 print(buffer.toString());
297 } else {
298 print(comment);
299 }
300 }
301
302
303
304 int nextBlock() throws IOException {
305 if (source == null || source.length() == 0) {
306 block = null;
307 return EOF;
308 }
309 if (source.startsWith("/*")) {
310
311 int i = source.indexOf("*/");
312 if (i == -1) {
313
314 block = source;
315 return CODE;
316 }
317 i += 2;
318 block = source.substring(0, i);
319 source = source.substring(i);
320 return COMMENT;
321 }
322
323
324 int i = findCommentStart(source, 0);
325 if (i != -1) {
326 block = source.substring(0, i);
327 source = source.substring(i);
328 } else {
329 block = source;
330 source = null;
331 }
332
333
334
335 line += countLines(block);
336
337 return CODE;
338 }
339
340
341
342
343
344
345 static int findCommentStart(String source, int fromIndex) {
346 if (fromIndex >= source.length()) {
347 return -1;
348 }
349
350 int commentStart = source.indexOf("/*", fromIndex);
351 if (commentStart == -1) {
352 return -1;
353 }
354
355 int commentLineStart = source.lastIndexOf("\n", commentStart);
356 if (commentLineStart == -1) {
357 commentLineStart = 0;
358 }
359 String line = source.substring(commentLineStart, commentStart + 2);
360
361 if (line.contains("//")) {
362 return findCommentStart(source, commentStart + 1);
363 } else if (countQuotes(line) % 2 == 1) {
364 return findCommentStart(source, commentStart + 1);
365 } else {
366 return commentStart;
367 }
368 }
369
370 static int countQuotes(String input) {
371 int result = 0;
372 for (int i = 0; i < input.length(); i++) {
373 if (input.charAt(i) == '\"') {
374 result++;
375 }
376 }
377 return result;
378 }
379
380 void substitute() {
381 for (int i = 0; i < oldTextStrings.size(); i++) {
382 String oldText = (String)oldTextStrings.elementAt(i);
383 String newText = (String)newTextStrings.elementAt(i);
384 int n;
385 while ((n = source.indexOf(oldText)) >= 0) {
386 source = source.substring(0, n) + newText +
387 source.substring(n + oldText.length());
388 }
389 }
390 }
391
392 public void process() throws IOException {
393
394 StringWriter sw = new StringWriter();
395 char[] buffer = new char[8192];
396 int n;
397 while ((n = in.read(buffer, 0, 8192)) > 0) {
398 sw.write(buffer, 0, n);
399 }
400 source = sw.toString();
401
402
403 substitute();
404
405
406 int blockType;
407 do {
408 blockType = nextBlock();
409 if (blockType == COMMENT) {
410 processComment(block);
411 } else if (blockType == CODE) {
412 print(block);
413 }
414 } while (blockType != EOF);
415
416
417 if (!stack.empty()) {
418 error("missing end statement(s)");
419 }
420 }
421
422
423
424
425 public static void usage() {
426 System.err.println("usage:" +
427 "\n java Munge [-D<symbol> ...] " +
428 "[-s <old>=<new> ...] " +
429 "[<in file>] [<out file>]" +
430 "\n java Munge [-D<symbol> ...] " +
431 "[-s <old>=<new> ...] " +
432 "<file> ... <directory>"
433 );
434 System.exit(1);
435 }
436 public static void usage(String msg) {
437 System.err.println(msg);
438 usage();
439 }
440
441
442
443
444 public static void main(String[] args) {
445
446
447 Object obj = new Object();
448
449
450 try {
451 args = CommandLine.parse( args );
452 } catch( IOException e ) {
453 usage("Unable to read @file argument.");
454 }
455
456
457 int iArg = 0;
458 while (iArg < args.length && args[iArg].startsWith("-")) {
459 if (args[iArg].startsWith("-D")) {
460 String symbol = args[iArg].substring(2);
461 symbols.put(symbol, obj);
462 }
463
464 else if (args[iArg].equals("-s")) {
465 if (iArg == args.length) {
466 usage("no substitution string specified for -s parameter");
467 }
468
469
470 String subst = args[++iArg];
471 int equals = subst.indexOf('=');
472 if (equals < 1 || equals >= subst.length()) {
473 usage("invalid substitution string \"" + subst + "\"");
474 }
475 String oldText = subst.substring(0, equals);
476 oldTextStrings.addElement(oldText);
477 String newText = subst.substring(equals + 1);
478 newTextStrings.addElement(newText);
479 }
480
481 else {
482 usage("invalid flag \"" + args[iArg] + "\"");
483 }
484
485 ++iArg;
486 }
487
488
489
490 String[] inFiles = new String[Math.max(args.length-iArg-1, 1)];
491 String[] outFiles = new String[inFiles.length];
492
493 if( iArg < args.length ) {
494 File targetDir = new File( args[args.length-1] );
495 if( targetDir.isDirectory() ) {
496 int i = 0;
497 for( ; iArg<args.length-1; i++, iArg++ ) {
498 inFiles[i] = args[iArg];
499 File inFile = new File( args[iArg] );
500 File outFile = new File( targetDir, inFile.getName() );
501 outFiles[i] = outFile.getAbsolutePath();
502 }
503 if( i == 0 ) {
504 usage("No source files specified.");
505 }
506 } else {
507 inFiles[0] = args[iArg++];
508 if( iArg < args.length ) {
509 outFiles[0] = args[iArg++];
510 }
511 if( iArg < args.length ) {
512 usage(args[args.length-1] + " is not a directory.");
513 }
514 }
515 }
516
517
518 for( int i=0; i<inFiles.length; i++ ) {
519
520 Munge munge = new Munge(inFiles[i], outFiles[i]);
521 if (munge.hasErrors()) {
522 munge.printErrorCount();
523 System.exit(munge.errors);
524 }
525
526 try {
527 munge.process();
528 munge.close();
529 } catch (IOException e) {
530 munge.error(e.toString());
531 }
532
533 if (munge.hasErrors()) {
534 munge.printErrorCount();
535 System.exit(munge.errors);
536 }
537 }
538 }
539
540
541
542
543
544
545
546
547 static class CommandLine {
548
549
550
551
552
553
554
555
556
557
558 static String[] parse(String[] args)
559 throws IOException
560 {
561 Vector newArgs = new Vector(args.length);
562 for (int i = 0; i < args.length; i++) {
563 String arg = args[i];
564 if (arg.length() > 1 && arg.charAt(0) == '@') {
565 arg = arg.substring(1);
566 if (arg.charAt(0) == '@') {
567 newArgs.addElement(arg);
568 } else {
569 loadCmdFile(arg, newArgs);
570 }
571 } else {
572 newArgs.addElement(arg);
573 }
574 }
575 String[] newArgsArray = new String[newArgs.size()];
576 newArgs.copyInto(newArgsArray);
577 return newArgsArray;
578 }
579
580 private static void loadCmdFile(String name, Vector args)
581 throws IOException
582 {
583 Reader r = new BufferedReader(new FileReader(name));
584 StreamTokenizer st = new StreamTokenizer(r);
585 st.resetSyntax();
586 st.wordChars(' ', 255);
587 st.whitespaceChars(0, ' ');
588 st.commentChar('#');
589 st.quoteChar('"');
590 st.quoteChar('\'');
591 while (st.nextToken() != st.TT_EOF) {
592 args.addElement(st.sval);
593 }
594 r.close();
595 }
596 }
597 }