blob: 37ef4518adf8632604c1162dbb3a93c7a9d667b1 [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);
231 else
232 return null;
233 }
234
235 Domain rover = domain;
236 while (rover != null) {
237 String result = doCommand(rover, args[0], args);
238 if (result != null)
239 return result;
240
241 rover = rover.getParent();
242 }
243
244 for (Object target : targets) {
245 String result = doCommand(target, args[0], args);
246 if (result != null)
247 return result;
248 }
249
250 return doCommand(this, args[0], args);
251 }
252
253 private String doCommand(Object target, String method, String[] args) {
254 if (target == null)
255 ; // System.err.println("Huh? Target should never be null " +
256 // domain);
257 else {
258 String cname = "_" + method.replaceAll("-", "_");
259 try {
260 Method m = target.getClass().getMethod(cname, new Class[] {
261 String[].class
262 });
263 return (String) m.invoke(target, new Object[] {
264 args
265 });
266 }
267 catch (NoSuchMethodException e) {
268 // Ignore
269 }
270 catch (InvocationTargetException e) {
271 if (e.getCause() instanceof IllegalArgumentException) {
272 reporter.error("%s, for cmd: %s, arguments; %s", e.getMessage(), method, Arrays.toString(args));
273 } else {
274 reporter.warning("Exception in replace: " + e.getCause());
275 e.getCause().printStackTrace();
276 }
277 }
278 catch (Exception e) {
279 reporter.warning("Exception in replace: " + e + " method=" + method);
280 e.printStackTrace();
281 }
282 }
283 return null;
284 }
285
286 /**
287 * Return a unique list where the duplicates are removed.
288 *
289 * @param args
290 * @return
291 */
292 static String _uniqHelp = "${uniq;<list> ...}";
293
294 public String _uniq(String args[]) {
295 verifyCommand(args, _uniqHelp, null, 1, Integer.MAX_VALUE);
296 Set<String> set = new LinkedHashSet<String>();
297 for (int i = 1; i < args.length; i++) {
298 set.addAll(ExtList.from(args[i].trim()));
299 }
300 ExtList<String> rsult = new ExtList<String>();
301 rsult.addAll(set);
302 return rsult.join(",");
303 }
304
305 public String _pathseparator(String args[]) {
306 return File.pathSeparator;
307 }
308
309 public String _separator(String args[]) {
310 return File.separator;
311 }
312
313 public String _filter(String args[]) {
314 return filter(args, false);
315 }
316
317 public String _filterout(String args[]) {
318 return filter(args, true);
319
320 }
321
322 static String _filterHelp = "${%s;<list>;<regex>}";
323
324 String filter(String[] args, boolean include) {
325 verifyCommand(args, String.format(_filterHelp, args[0]), null, 3, 3);
326
327 ExtList<String> list = ExtList.from(args[1]);
328 Pattern pattern = Pattern.compile(args[2]);
329
330 for (Iterator<String> i = list.iterator(); i.hasNext();) {
331 if (pattern.matcher(i.next()).matches() == include)
332 i.remove();
333 }
334 return list.join();
335 }
336
337 static String _sortHelp = "${sort;<list>...}";
338
339 public String _sort(String args[]) {
340 verifyCommand(args, _sortHelp, null, 2, Integer.MAX_VALUE);
341
342 ExtList<String> result = new ExtList<String>();
343 for (int i = 1; i < args.length; i++) {
344 result.addAll(ExtList.from(args[i]));
345 }
346 Collections.sort(result);
347 return result.join();
348 }
349
350 static String _joinHelp = "${join;<list>...}";
351
352 public String _join(String args[]) {
353
354 verifyCommand(args, _joinHelp, null, 1, Integer.MAX_VALUE);
355
356 ExtList<String> result = new ExtList<String>();
357 for (int i = 1; i < args.length; i++) {
358 result.addAll(ExtList.from(args[i]));
359 }
360 return result.join();
361 }
362
363 static String _ifHelp = "${if;<condition>;<iftrue> [;<iffalse>] }";
364
365 public String _if(String args[]) {
366 verifyCommand(args, _ifHelp, null, 3, 4);
367 String condition = args[1].trim();
368 if (!condition.equalsIgnoreCase("false"))
369 if (condition.length() != 0)
370 return args[2];
371
372 if (args.length > 3)
373 return args[3];
374 else
375 return "";
376 }
377
378 public String _now(String args[]) {
379 return new Date().toString();
380 }
381
382 public final static String _fmodifiedHelp = "${fmodified;<list of filenames>...}, return latest modification date";
383
384 public String _fmodified(String args[]) throws Exception {
385 verifyCommand(args, _fmodifiedHelp, null, 2, Integer.MAX_VALUE);
386
387 long time = 0;
388 Collection<String> names = new ExtList<String>();
389 for (int i = 1; i < args.length; i++) {
390 names.addAll(ExtList.from(args[i]));
391 }
392 for (String name : names) {
393 File f = new File(name);
394 if (f.exists() && f.lastModified() > time)
395 time = f.lastModified();
396 }
397 return "" + time;
398 }
399
400 public String _long2date(String args[]) {
401 try {
402 return new Date(Long.parseLong(args[1])).toString();
403 }
404 catch (Exception e) {
405 e.printStackTrace();
406 }
407 return "not a valid long";
408 }
409
410 public String _literal(String args[]) {
411 if (args.length != 2)
412 throw new RuntimeException("Need a value for the ${literal;<value>} macro");
413 return "${" + args[1] + "}";
414 }
415
416 public String _def(String args[]) {
417 if (args.length != 2)
418 throw new RuntimeException("Need a value for the ${def;<value>} macro");
419
420 String value = domain.getMap().get(args[1]);
421 if (value == null)
422 return "";
423
424 return value;
425 }
426
427 /**
428 * replace ; <list> ; regex ; replace
429 *
430 * @param args
431 * @return
432 */
433 public String _replace(String args[]) {
434 if (args.length != 4) {
435 reporter.warning("Invalid nr of arguments to replace " + Arrays.asList(args));
436 return null;
437 }
438
439 String list[] = args[1].split("\\s*,\\s*");
440 StringBuilder sb = new StringBuilder();
441 String del = "";
442 for (int i = 0; i < list.length; i++) {
443 String element = list[i].trim();
444 if (!element.equals("")) {
445 sb.append(del);
446 sb.append(element.replaceAll(args[2], args[3]));
447 del = ", ";
448 }
449 }
450
451 return sb.toString();
452 }
453
454 public String _warning(String args[]) {
455 for (int i = 1; i < args.length; i++) {
456 reporter.warning(process(args[i]));
457 }
458 return "";
459 }
460
461 public String _error(String args[]) {
462 for (int i = 1; i < args.length; i++) {
463 reporter.error(process(args[i]));
464 }
465 return "";
466 }
467
468 /**
469 * toclassname ; <path>.class ( , <path>.class ) *
470 *
471 * @param args
472 * @return
473 */
474 static String _toclassnameHelp = "${classname;<list of class names>}, convert class paths to FQN class names ";
475
476 public String _toclassname(String args[]) {
477 verifyCommand(args, _toclassnameHelp, null, 2, 2);
478 Collection<String> paths = ExtList.from(args[1]);
479
480 ExtList<String> names = new ExtList<String>(paths.size());
481 for (String path : paths) {
482 if (path.endsWith(".class")) {
483 String name = path.substring(0, path.length() - 6).replace('/', '.');
484 names.add(name);
485 } else if (path.endsWith(".java")) {
486 String name = path.substring(0, path.length() - 5).replace('/', '.');
487 names.add(name);
488 } else {
489 reporter.warning("in toclassname, %s, is not a class path because it does not end in .class", args[1]);
490 }
491 }
492 return names.join(",");
493 }
494
495 /**
496 * toclassname ; <path>.class ( , <path>.class ) *
497 *
498 * @param args
499 * @return
500 */
501
502 static String _toclasspathHelp = "${toclasspath;<list>[;boolean]}, convert a list of class names to paths";
503
504 public String _toclasspath(String args[]) {
505 verifyCommand(args, _toclasspathHelp, null, 2, 3);
506 boolean cl = true;
507 if (args.length > 2)
508 cl = Boolean.valueOf(args[2]);
509
510 ExtList<String> names = ExtList.from(args[1]);
511 ExtList<String> paths = new ExtList<String>(names.size());
512 for (String name : names) {
513 String path = name.replace('.', '/') + (cl ? ".class" : "");
514 paths.add(path);
515 }
516 return paths.join(",");
517 }
518
519 public String _dir(String args[]) {
520 if (args.length < 2) {
521 reporter.warning("Need at least one file name for ${dir;...}");
522 return null;
523 } else {
524 String del = "";
525 StringBuilder sb = new StringBuilder();
526 for (int i = 1; i < args.length; i++) {
527 File f = IO.getFile(base, args[i]);
528 if (f.exists() && f.getParentFile().exists()) {
529 sb.append(del);
530 sb.append(f.getParentFile().getAbsolutePath());
531 del = ",";
532 }
533 }
534 return sb.toString();
535 }
536
537 }
538
539 public String _basename(String args[]) {
540 if (args.length < 2) {
541 reporter.warning("Need at least one file name for ${basename;...}");
542 return null;
543 } else {
544 String del = "";
545 StringBuilder sb = new StringBuilder();
546 for (int i = 1; i < args.length; i++) {
547 File f = IO.getFile(base, args[i]);
548 if (f.exists() && f.getParentFile().exists()) {
549 sb.append(del);
550 sb.append(f.getName());
551 del = ",";
552 }
553 }
554 return sb.toString();
555 }
556
557 }
558
559 public String _isfile(String args[]) {
560 if (args.length < 2) {
561 reporter.warning("Need at least one file name for ${isfile;...}");
562 return null;
563 } else {
564 boolean isfile = true;
565 for (int i = 1; i < args.length; i++) {
566 File f = new File(args[i]).getAbsoluteFile();
567 isfile &= f.isFile();
568 }
569 return isfile ? "true" : "false";
570 }
571
572 }
573
574 public String _isdir(String args[]) {
575 if (args.length < 2) {
576 reporter.warning("Need at least one file name for ${isdir;...}");
577 return null;
578 } else {
579 boolean isdir = true;
580 for (int i = 1; i < args.length; i++) {
581 File f = new File(args[i]).getAbsoluteFile();
582 isdir &= f.isDirectory();
583 }
584 return isdir ? "true" : "false";
585 }
586
587 }
588
589 public String _tstamp(String args[]) {
590 String format = "yyyyMMddHHmm";
591 long now = System.currentTimeMillis();
592 TimeZone tz = TimeZone.getTimeZone("UTC");
593
594 if (args.length > 1) {
595 format = args[1];
596 }
597 if (args.length > 2) {
598 tz = TimeZone.getTimeZone(args[2]);
599 }
600 if (args.length > 3) {
601 now = Long.parseLong(args[3]);
602 }
603 if (args.length > 4) {
604 reporter.warning("Too many arguments for tstamp: " + Arrays.toString(args));
605 }
606
607 SimpleDateFormat sdf = new SimpleDateFormat(format);
608 sdf.setTimeZone(tz);
609
610 return sdf.format(new Date(now));
611 }
612
613 /**
614 * Wildcard a directory. The lists can contain Instruction that are matched
615 * against the given directory ${lsr;<dir>;<list>(;<list>)*}
616 * ${lsa;<dir>;<list>(;<list>)*}
617 *
618 * @author aqute
619 */
620
621 public String _lsr(String args[]) {
622 return ls(args, true);
623 }
624
625 public String _lsa(String args[]) {
626 return ls(args, false);
627 }
628
629 String ls(String args[], boolean relative) {
630 if (args.length < 2)
631 throw new IllegalArgumentException("the ${ls} macro must at least have a directory as parameter");
632
633 File dir = IO.getFile(base, args[1]);
634 if (!dir.isAbsolute())
635 throw new IllegalArgumentException("the ${ls} macro directory parameter is not absolute: " + dir);
636
637 if (!dir.exists())
638 throw new IllegalArgumentException("the ${ls} macro directory parameter does not exist: " + dir);
639
640 if (!dir.isDirectory())
641 throw new IllegalArgumentException(
642 "the ${ls} macro directory parameter points to a file instead of a directory: " + dir);
643
644 List<File> files = new ArrayList<File>(new SortedList<File>(dir.listFiles()));
645
646 for (int i = 2; i < args.length; i++) {
647 Glob filters = new Glob(args[i]);
648 filters.select(files);
649 }
650
651 ExtList<String> result = new ExtList<String>();
652 for (File file : files)
653 result.add(relative ? file.getName() : file.getAbsolutePath());
654
655 return result.join(",");
656 }
657
658 public String _currenttime(String args[]) {
659 return Long.toString(System.currentTimeMillis());
660 }
661
662 /**
663 * System command. Execute a command and insert the result.
664 *
665 * @param args
666 * @param help
667 * @param patterns
668 * @param low
669 * @param high
670 */
671 public String system_internal(boolean allowFail, String args[]) throws Exception {
672 verifyCommand(args, "${" + (allowFail ? "system-allow-fail" : "system")
673 + ";<command>[;<in>]}, execute a system command", null, 2, 3);
674 String command = args[1];
675 String input = null;
676
677 if (args.length > 2) {
678 input = args[2];
679 }
680
681 Process process = Runtime.getRuntime().exec(command, null, base);
682 if (input != null) {
683 process.getOutputStream().write(input.getBytes("UTF-8"));
684 }
685 process.getOutputStream().close();
686
687 String s = IO.collect(process.getInputStream(), "UTF-8");
688 int exitValue = process.waitFor();
689 if (exitValue != 0)
690 return exitValue + "";
691
692 if (!allowFail && (exitValue != 0)) {
693 reporter.error("System command " + command + " failed with " + exitValue);
694 }
695 return s.trim();
696 }
697
698 public String _system(String args[]) throws Exception {
699 return system_internal(false, args);
700 }
701
702 public String _system_allow_fail(String args[]) throws Exception {
703 String result = "";
704 try {
705 result = system_internal(true, args);
706 }
707 catch (Throwable t) {
708 /* ignore */
709 }
710 return result;
711 }
712
713 public String _env(String args[]) {
714 verifyCommand(args, "${env;<name>}, get the environmet variable", null, 2, 2);
715
716 try {
717 return System.getenv(args[1]);
718 }
719 catch (Throwable t) {
720 return null;
721 }
722 }
723
724 /**
725 * Get the contents of a file.
726 *
727 * @param in
728 * @return
729 * @throws IOException
730 */
731
732 public String _cat(String args[]) throws IOException {
733 verifyCommand(args, "${cat;<in>}, get the content of a file", null, 2, 2);
734 File f = IO.getFile(base, args[1]);
735 if (f.isFile()) {
736 return IO.collect(f);
737 } else if (f.isDirectory()) {
738 return Arrays.toString(f.list());
739 } else {
740 try {
741 URL url = new URL(args[1]);
742 return IO.collect(url, "UTF-8");
743 }
744 catch (MalformedURLException mfue) {
745 // Ignore here
746 }
747 return null;
748 }
749 }
750
751 public static void verifyCommand(String args[], String help, Pattern[] patterns, int low, int high) {
752 String message = "";
753 if (args.length > high) {
754 message = "too many arguments";
755 } else if (args.length < low) {
756 message = "too few arguments";
757 } else {
758 for (int i = 0; patterns != null && i < patterns.length && i < args.length; i++) {
759 if (patterns[i] != null) {
760 Matcher m = patterns[i].matcher(args[i]);
761 if (!m.matches())
Stuart McCulloch54229442012-07-12 22:12:58 +0000762 message += String.format("Argument %s (%s) does not match %s%n", i, args[i],
Stuart McCulloch1a890552012-06-29 19:23:09 +0000763 patterns[i].pattern());
764 }
765 }
766 }
767 if (message.length() != 0) {
768 StringBuilder sb = new StringBuilder();
769 String del = "${";
770 for (String arg : args) {
771 sb.append(del);
772 sb.append(arg);
773 del = ";";
774 }
775 sb.append("}, is not understood. ");
776 sb.append(message);
777 throw new IllegalArgumentException(sb.toString());
778 }
779 }
780
781 // Helper class to track expansion of variables
782 // on the stack.
783 static class Link {
784 Link previous;
785 String key;
786 Domain start;
787
788 public Link(Domain start, Link previous, String key) {
789 this.previous = previous;
790 this.key = key;
791 this.start = start;
792 }
793
794 public boolean contains(String key) {
795 if (this.key.equals(key))
796 return true;
797
798 if (previous == null)
799 return false;
800
801 return previous.contains(key);
802 }
803
804 public String toString() {
805 StringBuilder sb = new StringBuilder("[");
806 append(sb);
807 sb.append("]");
808 return sb.toString();
809 }
810
811 private void append(StringBuilder sb) {
812 if (previous != null) {
813 previous.append(sb);
814 sb.append(",");
815 }
816 sb.append(key);
817 }
818 }
819
820 /**
821 * Take all the properties and translate them to actual values. This method
822 * takes the set properties and traverse them over all entries, including
823 * the default properties for that properties. The values no longer contain
824 * macros.
825 *
826 * @return A new Properties with the flattened values
827 */
828 public Map<String,String> getFlattenedProperties() {
829 // Some macros only work in a lower Domain, so we
830 // do not report unknown macros while flattening
831 flattening = true;
832 try {
833 Map<String,String> flattened = new HashMap<String,String>();
834 Map<String,String> source = domain.getMap();
835 for (String key : source.keySet()) {
836 if (!key.startsWith("_"))
837 if (key.startsWith("-"))
838 flattened.put(key, source.get(key));
839 else
840 flattened.put(key, process(source.get(key)));
841 }
842 return flattened;
843 }
844 finally {
845 flattening = false;
846 }
847 }
848
849 public final static String _fileHelp = "${file;<base>;<paths>...}, create correct OS dependent path";
850
851 public String _osfile(String args[]) {
852 verifyCommand(args, _fileHelp, null, 3, 3);
853 File base = new File(args[1]);
854 File f = IO.getFile(base, args[2]);
855 return f.getAbsolutePath();
856 }
857
858 public String _path(String args[]) {
859 ExtList<String> list = new ExtList<String>();
860 for (int i = 1; i < args.length; i++) {
861 list.addAll(ExtList.from(args[i]));
862 }
863 return list.join(File.pathSeparator);
864 }
865
866 public static Properties getParent(Properties p) {
867 try {
868 Field f = Properties.class.getDeclaredField("defaults");
869 f.setAccessible(true);
870 return (Properties) f.get(p);
871 }
872 catch (Exception e) {
873 Field[] fields = Properties.class.getFields();
874 System.err.println(Arrays.toString(fields));
875 return null;
876 }
877 }
878
879 public String process(String line) {
880 return process(line, domain);
881 }
882
883 /**
884 * Generate a random string, which is guaranteed to be a valid Java
885 * identifier (first character is an ASCII letter, subsequent characters are
886 * ASCII letters or numbers). Takes an optional parameter for the length of
887 * string to generate; default is 8 characters.
888 */
889 public String _random(String[] args) {
890 int numchars = 8;
891 if (args.length > 1) {
892 try {
893 numchars = Integer.parseInt(args[1]);
894 }
895 catch (NumberFormatException e) {
896 throw new IllegalArgumentException("Invalid character count parameter in ${random} macro.");
897 }
898 }
899
900 char[] letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
901 char[] alphanums = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();
902
903 char[] array = new char[numchars];
904 for (int i = 0; i < numchars; i++) {
905 char c;
906 if (i == 0)
907 c = letters[random.nextInt(letters.length)];
908 else
909 c = alphanums[random.nextInt(alphanums.length)];
910 array[i] = c;
911 }
912
913 return new String(array);
914 }
915
916 public void setReporter(Reporter reporter) {
917 this.reporter = reporter;
918 }
919
920
921 public int _processors(String args[]) {
922 float multiplier = 1F;
923 if ( args.length > 1 )
924 multiplier = Float.parseFloat(args[1]);
925
926 return (int) (Runtime.getRuntime().availableProcessors() * multiplier);
927 }
928
929 public long _maxMemory(String args[]) {
930 return Runtime.getRuntime().maxMemory();
931 }
932 public long _freeMemory(String args[]) {
933 return Runtime.getRuntime().freeMemory();
934 }
935
936 public long _nanoTime(String args[]) {
937 return System.nanoTime();
938 }
939
940}