blob: 1bd8e07f662512e4d248d660030bf7b90d2e5dd6 [file] [log] [blame]
Stuart McCulloch1a890552012-06-29 19:23:09 +00001package aQute.libg.sed;
2
3import java.io.*;
4import java.lang.reflect.*;
5import java.net.*;
6import java.text.*;
7import java.util.*;
8import java.util.regex.*;
9
10import aQute.lib.collections.*;
11import aQute.lib.io.*;
12import aQute.libg.glob.*;
13import aQute.libg.reporter.*;
14import aQute.service.reporter.*;
15
16/**
17 * Provide a macro Domain. This Domain can replace variables in strings based on
18 * a properties and a domain. The domain can implement functions that start with
19 * a "_" and take args[], the names of these functions are available as
20 * functions in the macro Domain (without the _). Macros can nest to any depth
21 * but may not contain loops. Add POSIX macros: ${#parameter} String length.
22 * ${parameter%word} Remove smallest suffix pattern. ${parameter%%word} Remove
23 * largest suffix pattern. ${parameter#word} Remove smallest prefix pattern.
24 * ${parameter##word} Remove largest prefix pattern.
25 */
26public class ReplacerAdapter extends ReporterAdapter implements Replacer {
27 static final Random random = new Random();
28 static Pattern WILDCARD = Pattern.compile("[*?|[\\\\]\\(\\)]");
29 Domain domain;
30 List<Object> targets = new ArrayList<Object>();
31 boolean flattening;
32 File base = new File(System.getProperty("user.dir"));
33 Reporter reporter = this;
34
35 public ReplacerAdapter(Domain domain) {
36 this.domain = domain;
37 }
38
39 public ReplacerAdapter(final Map<String,String> domain) {
40 this(new Domain() {
41
42 public Map<String,String> getMap() {
43 return domain;
44 }
45
46 public Domain getParent() {
47 return null;
48 }
49
50 });
51 }
52
53 public ReplacerAdapter target(Object target) {
54 assert target != null;
55 targets.add(target);
56 return this;
57 }
58
59 public ReplacerAdapter target(File base) {
60 this.base = base;
61 return this;
62 }
63
64 public String process(String line, Domain source) {
65 return process(line, new Link(source, null, line));
66 }
67
68 String process(String line, Link link) {
69 StringBuilder sb = new StringBuilder();
70 process(line, 0, '\u0000', '\u0000', sb, link);
71 return sb.toString();
72 }
73
74 int process(CharSequence org, int index, char begin, char end, StringBuilder result, Link link) {
75 StringBuilder line = new StringBuilder(org);
76 int nesting = 1;
77
78 StringBuilder variable = new StringBuilder();
79 outer: while (index < line.length()) {
80 char c1 = line.charAt(index++);
81 if (c1 == end) {
82 if (--nesting == 0) {
83 result.append(replace(variable.toString(), link));
84 return index;
85 }
86 } else if (c1 == begin)
87 nesting++;
88 else if (c1 == '\\' && index < line.length() - 1 && line.charAt(index) == '$') {
89 // remove the escape backslash and interpret the dollar
90 // as a
91 // literal
92 index++;
93 variable.append('$');
94 continue outer;
95 } else if (c1 == '$' && index < line.length() - 2) {
96 char c2 = line.charAt(index);
97 char terminator = getTerminator(c2);
98 if (terminator != 0) {
99 index = process(line, index + 1, c2, terminator, variable, link);
100 continue outer;
101 }
102 } else if (c1 == '.' && index < line.length() && line.charAt(index) == '/') {
103 // Found the sequence ./
104 if (index == 1 || Character.isWhitespace(line.charAt(index - 2))) {
105 // make sure it is preceded by whitespace or starts at begin
106 index++;
107 variable.append(base.getAbsolutePath());
108 variable.append('/');
109 continue outer;
110 }
111 }
112 variable.append(c1);
113 }
114 result.append(variable);
115 return index;
116 }
117
118 public static char getTerminator(char c) {
119 switch (c) {
120 case '(' :
121 return ')';
122 case '[' :
123 return ']';
124 case '{' :
125 return '}';
126 case '<' :
127 return '>';
128 case '\u00ab' : // Guillemet double << >>
129 return '\u00bb';
130 case '\u2039' : // Guillemet single
131 return '\u203a';
132 }
133 return 0;
134 }
135
136 public String getProcessed(String key) {
137 return replace(key, null);
138 }
139
140 protected String replace(String key, Link link) {
141 if (link != null && link.contains(key))
142 return "${infinite:" + link.toString() + "}";
143
144 if (key != null) {
145 key = key.trim();
146 if (key.length() > 0) {
147 Domain source = domain;
148 String value = null;
149 if (key.indexOf(';') < 0) {
150 if (WILDCARD.matcher(key).find()) {
151 Glob ins = new Glob(key);
152 StringBuilder sb = new StringBuilder();
153 String del = "";
154 for (String k : getAllKeys()) {
155 if (ins.matcher(k).find()) {
156 String v = replace(k, new Link(source, link, key));
157 if (v != null) {
158 sb.append(del);
159 del = ",";
160 sb.append(v);
161 }
162 }
163 }
164 return sb.toString();
165 }
166
167 while (value == null && source != null) {
168 value = source.getMap().get(key);
169 if (value != null)
170 return process(value, new Link(source, link, key));
171
172 source = source.getParent();
173 }
174 }
175 value = doCommands(key, link);
176 if (value != null)
177 return process(value, new Link(source, link, key));
178
179 if (key != null && key.trim().length() > 0) {
180 value = System.getProperty(key);
181 if (value != null)
182 return value;
183 }
184 if (!flattening && !key.equals("@"))
185 reporter.warning("No translation found for macro: " + key);
186 } else {
187 reporter.warning("Found empty macro key");
188 }
189 } else {
190 reporter.warning("Found null macro key");
191 }
192 return "${" + key + "}";
193 }
194
195 private List<String> getAllKeys() {
196 List<String> l = new ArrayList<String>();
197 Domain source = domain;
198 do {
199 l.addAll(source.getMap().keySet());
200 source = source.getParent();
201 } while (source != null);
202
203 Collections.sort(l);
204 return l;
205 }
206
207 /**
208 * Parse the key as a command. A command consist of parameters separated by
209 * ':'.
210 *
211 * @param key
212 * @return
213 */
214 static Pattern commands = Pattern.compile("(?<!\\\\);");
215
216 private String doCommands(String key, Link source) {
217 String[] args = commands.split(key);
218 if (args == null || args.length == 0)
219 return null;
220
221 for (int i = 0; i < args.length; i++)
222 if (args[i].indexOf('\\') >= 0)
223 args[i] = args[i].replaceAll("\\\\;", ";");
224
225 if (args[0].startsWith("^")) {
226 String varname = args[0].substring(1).trim();
227
228 Domain parent = source.start.getParent();
229 if (parent != null)
230 return parent.getMap().get(varname);
Stuart McCulloch2929e2d2012-08-07 10:57:21 +0000231 return null;
Stuart McCulloch1a890552012-06-29 19:23:09 +0000232 }
233
234 Domain rover = domain;
235 while (rover != null) {
236 String result = doCommand(rover, args[0], args);
237 if (result != null)
238 return result;
239
240 rover = rover.getParent();
241 }
242
243 for (Object target : targets) {
244 String result = doCommand(target, args[0], args);
245 if (result != null)
246 return result;
247 }
248
249 return doCommand(this, args[0], args);
250 }
251
252 private String doCommand(Object target, String method, String[] args) {
253 if (target == null)
254 ; // System.err.println("Huh? Target should never be null " +
255 // domain);
256 else {
257 String cname = "_" + method.replaceAll("-", "_");
258 try {
259 Method m = target.getClass().getMethod(cname, new Class[] {
260 String[].class
261 });
262 return (String) m.invoke(target, new Object[] {
263 args
264 });
265 }
266 catch (NoSuchMethodException e) {
267 // Ignore
268 }
269 catch (InvocationTargetException e) {
270 if (e.getCause() instanceof IllegalArgumentException) {
Stuart McCulloch2a0afd62012-09-06 18:28:06 +0000271 reporter.error("%s, for cmd: %s, arguments; %s", e.getCause().getMessage(), method, Arrays.toString(args));
Stuart McCulloch1a890552012-06-29 19:23:09 +0000272 } else {
273 reporter.warning("Exception in replace: " + e.getCause());
274 e.getCause().printStackTrace();
275 }
276 }
277 catch (Exception e) {
278 reporter.warning("Exception in replace: " + e + " method=" + method);
279 e.printStackTrace();
280 }
281 }
282 return null;
283 }
284
285 /**
286 * Return a unique list where the duplicates are removed.
287 *
288 * @param args
289 * @return
290 */
291 static String _uniqHelp = "${uniq;<list> ...}";
292
293 public String _uniq(String args[]) {
294 verifyCommand(args, _uniqHelp, null, 1, Integer.MAX_VALUE);
295 Set<String> set = new LinkedHashSet<String>();
296 for (int i = 1; i < args.length; i++) {
297 set.addAll(ExtList.from(args[i].trim()));
298 }
299 ExtList<String> rsult = new ExtList<String>();
300 rsult.addAll(set);
301 return rsult.join(",");
302 }
303
304 public String _pathseparator(String args[]) {
305 return File.pathSeparator;
306 }
307
308 public String _separator(String args[]) {
309 return File.separator;
310 }
311
312 public String _filter(String args[]) {
313 return filter(args, false);
314 }
315
316 public String _filterout(String args[]) {
317 return filter(args, true);
318
319 }
320
321 static String _filterHelp = "${%s;<list>;<regex>}";
322
323 String filter(String[] args, boolean include) {
324 verifyCommand(args, String.format(_filterHelp, args[0]), null, 3, 3);
325
326 ExtList<String> list = ExtList.from(args[1]);
327 Pattern pattern = Pattern.compile(args[2]);
328
329 for (Iterator<String> i = list.iterator(); i.hasNext();) {
330 if (pattern.matcher(i.next()).matches() == include)
331 i.remove();
332 }
333 return list.join();
334 }
335
336 static String _sortHelp = "${sort;<list>...}";
337
338 public String _sort(String args[]) {
339 verifyCommand(args, _sortHelp, null, 2, Integer.MAX_VALUE);
340
341 ExtList<String> result = new ExtList<String>();
342 for (int i = 1; i < args.length; i++) {
343 result.addAll(ExtList.from(args[i]));
344 }
345 Collections.sort(result);
346 return result.join();
347 }
348
349 static String _joinHelp = "${join;<list>...}";
350
351 public String _join(String args[]) {
352
353 verifyCommand(args, _joinHelp, null, 1, Integer.MAX_VALUE);
354
355 ExtList<String> result = new ExtList<String>();
356 for (int i = 1; i < args.length; i++) {
357 result.addAll(ExtList.from(args[i]));
358 }
359 return result.join();
360 }
361
362 static String _ifHelp = "${if;<condition>;<iftrue> [;<iffalse>] }";
363
364 public String _if(String args[]) {
365 verifyCommand(args, _ifHelp, null, 3, 4);
366 String condition = args[1].trim();
367 if (!condition.equalsIgnoreCase("false"))
368 if (condition.length() != 0)
369 return args[2];
370
371 if (args.length > 3)
372 return args[3];
Stuart McCulloch2929e2d2012-08-07 10:57:21 +0000373 return "";
Stuart McCulloch1a890552012-06-29 19:23:09 +0000374 }
375
376 public String _now(String args[]) {
377 return new Date().toString();
378 }
379
380 public final static String _fmodifiedHelp = "${fmodified;<list of filenames>...}, return latest modification date";
381
382 public String _fmodified(String args[]) throws Exception {
383 verifyCommand(args, _fmodifiedHelp, null, 2, Integer.MAX_VALUE);
384
385 long time = 0;
386 Collection<String> names = new ExtList<String>();
387 for (int i = 1; i < args.length; i++) {
388 names.addAll(ExtList.from(args[i]));
389 }
390 for (String name : names) {
391 File f = new File(name);
392 if (f.exists() && f.lastModified() > time)
393 time = f.lastModified();
394 }
395 return "" + time;
396 }
397
398 public String _long2date(String args[]) {
399 try {
400 return new Date(Long.parseLong(args[1])).toString();
401 }
402 catch (Exception e) {
403 e.printStackTrace();
404 }
405 return "not a valid long";
406 }
407
408 public String _literal(String args[]) {
409 if (args.length != 2)
410 throw new RuntimeException("Need a value for the ${literal;<value>} macro");
411 return "${" + args[1] + "}";
412 }
413
414 public String _def(String args[]) {
415 if (args.length != 2)
416 throw new RuntimeException("Need a value for the ${def;<value>} macro");
417
418 String value = domain.getMap().get(args[1]);
419 if (value == null)
420 return "";
421
422 return value;
423 }
424
425 /**
426 * replace ; <list> ; regex ; replace
427 *
428 * @param args
429 * @return
430 */
431 public String _replace(String args[]) {
432 if (args.length != 4) {
433 reporter.warning("Invalid nr of arguments to replace " + Arrays.asList(args));
434 return null;
435 }
436
437 String list[] = args[1].split("\\s*,\\s*");
438 StringBuilder sb = new StringBuilder();
439 String del = "";
440 for (int i = 0; i < list.length; i++) {
441 String element = list[i].trim();
442 if (!element.equals("")) {
443 sb.append(del);
444 sb.append(element.replaceAll(args[2], args[3]));
445 del = ", ";
446 }
447 }
448
449 return sb.toString();
450 }
451
452 public String _warning(String args[]) {
453 for (int i = 1; i < args.length; i++) {
454 reporter.warning(process(args[i]));
455 }
456 return "";
457 }
458
459 public String _error(String args[]) {
460 for (int i = 1; i < args.length; i++) {
461 reporter.error(process(args[i]));
462 }
463 return "";
464 }
465
466 /**
467 * toclassname ; <path>.class ( , <path>.class ) *
468 *
469 * @param args
470 * @return
471 */
472 static String _toclassnameHelp = "${classname;<list of class names>}, convert class paths to FQN class names ";
473
474 public String _toclassname(String args[]) {
475 verifyCommand(args, _toclassnameHelp, null, 2, 2);
476 Collection<String> paths = ExtList.from(args[1]);
477
478 ExtList<String> names = new ExtList<String>(paths.size());
479 for (String path : paths) {
480 if (path.endsWith(".class")) {
481 String name = path.substring(0, path.length() - 6).replace('/', '.');
482 names.add(name);
483 } else if (path.endsWith(".java")) {
484 String name = path.substring(0, path.length() - 5).replace('/', '.');
485 names.add(name);
486 } else {
487 reporter.warning("in toclassname, %s, is not a class path because it does not end in .class", args[1]);
488 }
489 }
490 return names.join(",");
491 }
492
493 /**
494 * toclassname ; <path>.class ( , <path>.class ) *
495 *
496 * @param args
497 * @return
498 */
499
500 static String _toclasspathHelp = "${toclasspath;<list>[;boolean]}, convert a list of class names to paths";
501
502 public String _toclasspath(String args[]) {
503 verifyCommand(args, _toclasspathHelp, null, 2, 3);
504 boolean cl = true;
505 if (args.length > 2)
506 cl = Boolean.valueOf(args[2]);
507
508 ExtList<String> names = ExtList.from(args[1]);
509 ExtList<String> paths = new ExtList<String>(names.size());
510 for (String name : names) {
511 String path = name.replace('.', '/') + (cl ? ".class" : "");
512 paths.add(path);
513 }
514 return paths.join(",");
515 }
516
517 public String _dir(String args[]) {
518 if (args.length < 2) {
519 reporter.warning("Need at least one file name for ${dir;...}");
520 return null;
Stuart McCulloch1a890552012-06-29 19:23:09 +0000521 }
Stuart McCulloch2929e2d2012-08-07 10:57:21 +0000522 String del = "";
523 StringBuilder sb = new StringBuilder();
524 for (int i = 1; i < args.length; i++) {
525 File f = IO.getFile(base, args[i]);
526 if (f.exists() && f.getParentFile().exists()) {
527 sb.append(del);
528 sb.append(f.getParentFile().getAbsolutePath());
529 del = ",";
530 }
531 }
532 return sb.toString();
Stuart McCulloch1a890552012-06-29 19:23:09 +0000533
534 }
535
536 public String _basename(String args[]) {
537 if (args.length < 2) {
538 reporter.warning("Need at least one file name for ${basename;...}");
539 return null;
Stuart McCulloch1a890552012-06-29 19:23:09 +0000540 }
Stuart McCulloch2929e2d2012-08-07 10:57:21 +0000541 String del = "";
542 StringBuilder sb = new StringBuilder();
543 for (int i = 1; i < args.length; i++) {
544 File f = IO.getFile(base, args[i]);
545 if (f.exists() && f.getParentFile().exists()) {
546 sb.append(del);
547 sb.append(f.getName());
548 del = ",";
549 }
550 }
551 return sb.toString();
Stuart McCulloch1a890552012-06-29 19:23:09 +0000552
553 }
554
555 public String _isfile(String args[]) {
556 if (args.length < 2) {
557 reporter.warning("Need at least one file name for ${isfile;...}");
558 return null;
Stuart McCulloch1a890552012-06-29 19:23:09 +0000559 }
Stuart McCulloch2929e2d2012-08-07 10:57:21 +0000560 boolean isfile = true;
561 for (int i = 1; i < args.length; i++) {
562 File f = new File(args[i]).getAbsoluteFile();
563 isfile &= f.isFile();
564 }
565 return isfile ? "true" : "false";
Stuart McCulloch1a890552012-06-29 19:23:09 +0000566
567 }
568
569 public String _isdir(String args[]) {
570 if (args.length < 2) {
571 reporter.warning("Need at least one file name for ${isdir;...}");
572 return null;
Stuart McCulloch1a890552012-06-29 19:23:09 +0000573 }
Stuart McCulloch2929e2d2012-08-07 10:57:21 +0000574 boolean isdir = true;
575 for (int i = 1; i < args.length; i++) {
576 File f = new File(args[i]).getAbsoluteFile();
577 isdir &= f.isDirectory();
578 }
579 return isdir ? "true" : "false";
Stuart McCulloch1a890552012-06-29 19:23:09 +0000580
581 }
582
583 public String _tstamp(String args[]) {
584 String format = "yyyyMMddHHmm";
585 long now = System.currentTimeMillis();
586 TimeZone tz = TimeZone.getTimeZone("UTC");
587
588 if (args.length > 1) {
589 format = args[1];
590 }
591 if (args.length > 2) {
592 tz = TimeZone.getTimeZone(args[2]);
593 }
594 if (args.length > 3) {
595 now = Long.parseLong(args[3]);
596 }
597 if (args.length > 4) {
598 reporter.warning("Too many arguments for tstamp: " + Arrays.toString(args));
599 }
600
601 SimpleDateFormat sdf = new SimpleDateFormat(format);
602 sdf.setTimeZone(tz);
603
604 return sdf.format(new Date(now));
605 }
606
607 /**
608 * Wildcard a directory. The lists can contain Instruction that are matched
609 * against the given directory ${lsr;<dir>;<list>(;<list>)*}
610 * ${lsa;<dir>;<list>(;<list>)*}
611 *
612 * @author aqute
613 */
614
615 public String _lsr(String args[]) {
616 return ls(args, true);
617 }
618
619 public String _lsa(String args[]) {
620 return ls(args, false);
621 }
622
623 String ls(String args[], boolean relative) {
624 if (args.length < 2)
625 throw new IllegalArgumentException("the ${ls} macro must at least have a directory as parameter");
626
627 File dir = IO.getFile(base, args[1]);
628 if (!dir.isAbsolute())
629 throw new IllegalArgumentException("the ${ls} macro directory parameter is not absolute: " + dir);
630
631 if (!dir.exists())
632 throw new IllegalArgumentException("the ${ls} macro directory parameter does not exist: " + dir);
633
634 if (!dir.isDirectory())
635 throw new IllegalArgumentException(
636 "the ${ls} macro directory parameter points to a file instead of a directory: " + dir);
637
638 List<File> files = new ArrayList<File>(new SortedList<File>(dir.listFiles()));
639
640 for (int i = 2; i < args.length; i++) {
641 Glob filters = new Glob(args[i]);
642 filters.select(files);
643 }
644
645 ExtList<String> result = new ExtList<String>();
646 for (File file : files)
647 result.add(relative ? file.getName() : file.getAbsolutePath());
648
649 return result.join(",");
650 }
651
652 public String _currenttime(String args[]) {
653 return Long.toString(System.currentTimeMillis());
654 }
655
656 /**
657 * System command. Execute a command and insert the result.
658 *
659 * @param args
660 * @param help
661 * @param patterns
662 * @param low
663 * @param high
664 */
665 public String system_internal(boolean allowFail, String args[]) throws Exception {
666 verifyCommand(args, "${" + (allowFail ? "system-allow-fail" : "system")
667 + ";<command>[;<in>]}, execute a system command", null, 2, 3);
668 String command = args[1];
669 String input = null;
670
671 if (args.length > 2) {
672 input = args[2];
673 }
674
675 Process process = Runtime.getRuntime().exec(command, null, base);
676 if (input != null) {
677 process.getOutputStream().write(input.getBytes("UTF-8"));
678 }
679 process.getOutputStream().close();
680
681 String s = IO.collect(process.getInputStream(), "UTF-8");
682 int exitValue = process.waitFor();
683 if (exitValue != 0)
684 return exitValue + "";
685
686 if (!allowFail && (exitValue != 0)) {
687 reporter.error("System command " + command + " failed with " + exitValue);
688 }
689 return s.trim();
690 }
691
692 public String _system(String args[]) throws Exception {
693 return system_internal(false, args);
694 }
695
696 public String _system_allow_fail(String args[]) throws Exception {
697 String result = "";
698 try {
699 result = system_internal(true, args);
700 }
701 catch (Throwable t) {
702 /* ignore */
703 }
704 return result;
705 }
706
707 public String _env(String args[]) {
708 verifyCommand(args, "${env;<name>}, get the environmet variable", null, 2, 2);
709
710 try {
711 return System.getenv(args[1]);
712 }
713 catch (Throwable t) {
714 return null;
715 }
716 }
717
718 /**
719 * Get the contents of a file.
720 *
721 * @param in
722 * @return
723 * @throws IOException
724 */
725
726 public String _cat(String args[]) throws IOException {
727 verifyCommand(args, "${cat;<in>}, get the content of a file", null, 2, 2);
728 File f = IO.getFile(base, args[1]);
729 if (f.isFile()) {
730 return IO.collect(f);
731 } else if (f.isDirectory()) {
732 return Arrays.toString(f.list());
733 } else {
734 try {
735 URL url = new URL(args[1]);
736 return IO.collect(url, "UTF-8");
737 }
738 catch (MalformedURLException mfue) {
739 // Ignore here
740 }
741 return null;
742 }
743 }
744
745 public static void verifyCommand(String args[], String help, Pattern[] patterns, int low, int high) {
746 String message = "";
747 if (args.length > high) {
748 message = "too many arguments";
749 } else if (args.length < low) {
750 message = "too few arguments";
751 } else {
752 for (int i = 0; patterns != null && i < patterns.length && i < args.length; i++) {
753 if (patterns[i] != null) {
754 Matcher m = patterns[i].matcher(args[i]);
755 if (!m.matches())
Stuart McCulloch54229442012-07-12 22:12:58 +0000756 message += String.format("Argument %s (%s) does not match %s%n", i, args[i],
Stuart McCulloch1a890552012-06-29 19:23:09 +0000757 patterns[i].pattern());
758 }
759 }
760 }
761 if (message.length() != 0) {
762 StringBuilder sb = new StringBuilder();
763 String del = "${";
764 for (String arg : args) {
765 sb.append(del);
766 sb.append(arg);
767 del = ";";
768 }
769 sb.append("}, is not understood. ");
770 sb.append(message);
771 throw new IllegalArgumentException(sb.toString());
772 }
773 }
774
775 // Helper class to track expansion of variables
776 // on the stack.
777 static class Link {
778 Link previous;
779 String key;
780 Domain start;
781
782 public Link(Domain start, Link previous, String key) {
783 this.previous = previous;
784 this.key = key;
785 this.start = start;
786 }
787
788 public boolean contains(String key) {
789 if (this.key.equals(key))
790 return true;
791
792 if (previous == null)
793 return false;
794
795 return previous.contains(key);
796 }
797
Stuart McCulloch2929e2d2012-08-07 10:57:21 +0000798 @Override
Stuart McCulloch1a890552012-06-29 19:23:09 +0000799 public String toString() {
800 StringBuilder sb = new StringBuilder("[");
801 append(sb);
802 sb.append("]");
803 return sb.toString();
804 }
805
806 private void append(StringBuilder sb) {
807 if (previous != null) {
808 previous.append(sb);
809 sb.append(",");
810 }
811 sb.append(key);
812 }
813 }
814
815 /**
816 * Take all the properties and translate them to actual values. This method
817 * takes the set properties and traverse them over all entries, including
818 * the default properties for that properties. The values no longer contain
819 * macros.
820 *
821 * @return A new Properties with the flattened values
822 */
823 public Map<String,String> getFlattenedProperties() {
824 // Some macros only work in a lower Domain, so we
825 // do not report unknown macros while flattening
826 flattening = true;
827 try {
828 Map<String,String> flattened = new HashMap<String,String>();
829 Map<String,String> source = domain.getMap();
830 for (String key : source.keySet()) {
831 if (!key.startsWith("_"))
832 if (key.startsWith("-"))
833 flattened.put(key, source.get(key));
834 else
835 flattened.put(key, process(source.get(key)));
836 }
837 return flattened;
838 }
839 finally {
840 flattening = false;
841 }
842 }
843
844 public final static String _fileHelp = "${file;<base>;<paths>...}, create correct OS dependent path";
845
846 public String _osfile(String args[]) {
847 verifyCommand(args, _fileHelp, null, 3, 3);
848 File base = new File(args[1]);
849 File f = IO.getFile(base, args[2]);
850 return f.getAbsolutePath();
851 }
852
853 public String _path(String args[]) {
854 ExtList<String> list = new ExtList<String>();
855 for (int i = 1; i < args.length; i++) {
856 list.addAll(ExtList.from(args[i]));
857 }
858 return list.join(File.pathSeparator);
859 }
860
861 public static Properties getParent(Properties p) {
862 try {
863 Field f = Properties.class.getDeclaredField("defaults");
864 f.setAccessible(true);
865 return (Properties) f.get(p);
866 }
867 catch (Exception e) {
868 Field[] fields = Properties.class.getFields();
869 System.err.println(Arrays.toString(fields));
870 return null;
871 }
872 }
873
874 public String process(String line) {
875 return process(line, domain);
876 }
877
878 /**
879 * Generate a random string, which is guaranteed to be a valid Java
880 * identifier (first character is an ASCII letter, subsequent characters are
881 * ASCII letters or numbers). Takes an optional parameter for the length of
882 * string to generate; default is 8 characters.
883 */
884 public String _random(String[] args) {
885 int numchars = 8;
886 if (args.length > 1) {
887 try {
888 numchars = Integer.parseInt(args[1]);
889 }
890 catch (NumberFormatException e) {
891 throw new IllegalArgumentException("Invalid character count parameter in ${random} macro.");
892 }
893 }
894
895 char[] letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
896 char[] alphanums = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();
897
898 char[] array = new char[numchars];
899 for (int i = 0; i < numchars; i++) {
900 char c;
901 if (i == 0)
902 c = letters[random.nextInt(letters.length)];
903 else
904 c = alphanums[random.nextInt(alphanums.length)];
905 array[i] = c;
906 }
907
908 return new String(array);
909 }
910
911 public void setReporter(Reporter reporter) {
912 this.reporter = reporter;
913 }
914
915
916 public int _processors(String args[]) {
917 float multiplier = 1F;
918 if ( args.length > 1 )
919 multiplier = Float.parseFloat(args[1]);
920
921 return (int) (Runtime.getRuntime().availableProcessors() * multiplier);
922 }
923
924 public long _maxMemory(String args[]) {
925 return Runtime.getRuntime().maxMemory();
926 }
927 public long _freeMemory(String args[]) {
928 return Runtime.getRuntime().freeMemory();
929 }
930
931 public long _nanoTime(String args[]) {
932 return System.nanoTime();
933 }
934
935}