1 package org.metricshub.jawk.jrt;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 import java.io.FileOutputStream;
32 import java.io.FileInputStream;
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.io.InputStreamReader;
36 import java.io.PrintStream;
37 import java.nio.charset.StandardCharsets;
38 import java.util.ArrayList;
39 import java.util.Date;
40 import java.util.Enumeration;
41 import java.util.HashMap;
42 import java.util.HashSet;
43 import java.util.IllegalFormatException;
44 import java.util.List;
45 import java.util.Locale;
46 import java.util.Map;
47 import java.util.Set;
48 import java.util.StringTokenizer;
49 import java.util.regex.Matcher;
50 import java.util.regex.Pattern;
51 import java.math.BigDecimal;
52 import org.metricshub.jawk.intermediate.UninitializedObject;
53 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
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 public class JRT {
90
91 private static final boolean IS_WINDOWS = System.getProperty("os.name").indexOf("Windows") >= 0;
92
93 private VariableManager vm;
94
95 private Map<String, Process> outputProcesses = new HashMap<String, Process>();
96 private Map<String, PrintStream> outputStreams = new HashMap<String, PrintStream>();
97
98 private PrintStream output = System.out;
99
100 private PrintStream error = System.err;
101
102
103 private PartitioningReader partitioningReader = null;
104
105 private String inputLine = null;
106
107 private List<String> inputFields = new ArrayList<String>(100);
108 private AssocArray arglistAa = null;
109 private int arglistIdx;
110 private boolean hasFilenames = false;
111 private static final UninitializedObject BLANK = new UninitializedObject();
112
113 private static final Integer ONE = Integer.valueOf(1);
114 private static final Integer ZERO = Integer.valueOf(0);
115 private static final Integer MINUS_ONE = Integer.valueOf(-1);
116 private String jrtInputString;
117
118 private Map<String, PartitioningReader> fileReaders = new HashMap<String, PartitioningReader>();
119 private Map<String, PartitioningReader> commandReaders = new HashMap<String, PartitioningReader>();
120 private Map<String, Process> commandProcesses = new HashMap<String, Process>();
121 private Map<String, PrintStream> outputFiles = new HashMap<String, PrintStream>();
122
123
124
125
126
127
128 @SuppressFBWarnings(value = "EI_EXPOSE_REP2", justification = "JRT must hold the provided VariableManager for later use")
129 public JRT(VariableManager vm) {
130 this.vm = vm;
131 }
132
133
134
135
136
137
138
139 public void setStreams(PrintStream ps, PrintStream err) {
140 output = ps == null ? System.out : ps;
141 error = err == null ? System.err : err;
142 }
143
144
145
146
147
148
149
150 public final void assignInitialVariables(Map<String, Object> initialVarMap) {
151 assert initialVarMap != null;
152 for (Map.Entry<String, Object> var : initialVarMap.entrySet()) {
153 vm.assignVariable(var.getKey(), var.getValue());
154 }
155 }
156
157
158
159
160
161
162
163
164
165
166 public static void assignEnvironmentVariables(AssocArray aa) {
167 assert aa.keySet().isEmpty();
168 Map<String, String> env = System.getenv();
169 for (Map.Entry<String, String> var : env.entrySet()) {
170 aa.put(var.getKey(), var.getValue());
171 }
172 }
173
174
175
176
177
178
179
180
181
182
183 public static String toAwkString(Object o, String convfmt, Locale locale) {
184 if (o == null) {
185 return "";
186 }
187 if (o instanceof Number) {
188
189 double d = ((Number) o).doubleValue();
190 if (isActuallyLong(d)) {
191
192 return Long.toString((long) Math.rint(d));
193 } else {
194
195 try {
196 String s = String.format(locale, convfmt, d);
197
198
199
200 if ((s.indexOf('.') > -1 || s.indexOf(',') > -1) && (s.indexOf('e') + s.indexOf('E') == -2)) {
201 while (s.endsWith("0")) {
202 s = s.substring(0, s.length() - 1);
203 }
204 if (s.endsWith(".") || s.endsWith(",")) {
205 s = s.substring(0, s.length() - 1);
206 }
207 }
208 return s;
209 } catch (java.util.UnknownFormatConversionException ufce) {
210
211 return "";
212 }
213 }
214 } else {
215
216 return o.toString();
217 }
218 }
219
220
221
222
223
224
225
226
227
228
229
230
231 public static String toAwkStringForOutput(Object o, String ofmt, Locale locale) {
232
233
234
235 if (!(o instanceof Number)) {
236 try {
237 o = new BigDecimal(o.toString()).doubleValue();
238 } catch (NumberFormatException e) {
239 }
240 }
241
242 return toAwkString(o, ofmt, locale);
243 }
244
245
246
247
248
249
250
251 public static double toDouble(final Object o) {
252 if (o == null) {
253 return 0;
254 }
255
256 if (o instanceof Number) {
257 return ((Number) o).doubleValue();
258 }
259
260 if (o instanceof Character) {
261 return (double) ((Character) o).charValue();
262 }
263
264
265 String s = o.toString();
266 int length = s.length();
267
268
269
270 if (length > 26) {
271 length = 26;
272 }
273
274
275
276
277 while (length > 0) {
278 try {
279 return Double.parseDouble(s.substring(0, length));
280 } catch (NumberFormatException nfe) {
281 length--;
282 }
283 }
284
285
286 return 0;
287 }
288
289
290
291
292
293
294
295
296 public static boolean isActuallyLong(double d) {
297 double r = Math.rint(d);
298 return Math.abs(d - r) < Math.ulp(d);
299 }
300
301
302
303
304
305
306
307 public static long toLong(final Object o) {
308 if (o == null) {
309 return 0;
310 }
311
312 if (o instanceof Number) {
313 return ((Number) o).longValue();
314 }
315
316 if (o instanceof Character) {
317 return (long) ((Character) o).charValue();
318 }
319
320
321 String s = o.toString();
322 int length = s.length();
323
324
325
326 if (length > 20) {
327 length = 20;
328 }
329
330
331
332
333 while (length > 0) {
334 try {
335 return Long.parseLong(s.substring(0, length));
336 } catch (NumberFormatException nfe) {
337 length--;
338 }
339 }
340
341 return 0;
342 }
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359 public static boolean compare2(Object o1, Object o2, int mode) {
360
361 String o1String = o1.toString();
362 String o2String = o2.toString();
363
364
365 if (o1 instanceof UninitializedObject) {
366 if (o2 instanceof UninitializedObject || "".equals(o2String) || "0".equals(o2String)) {
367 return mode == 0;
368 } else {
369 return mode < 0;
370 }
371 }
372 if (o2 instanceof UninitializedObject) {
373 if ("".equals(o1String) || "0".equals(o1String)) {
374 return mode == 0;
375 } else {
376 return mode > 0;
377 }
378 }
379
380 if (!(o1 instanceof Number)) {
381 try {
382 o1 = new BigDecimal(o1String).doubleValue();
383 } catch (NumberFormatException nfe) {
384
385 }
386 }
387 if (!(o2 instanceof Number)) {
388 try {
389 o2 = new BigDecimal(o2String).doubleValue();
390 } catch (NumberFormatException nfe) {
391
392 }
393 }
394
395 if ((o1 instanceof Number) && (o2 instanceof Number)) {
396 if (mode < 0) {
397 return ((Number) o1).doubleValue() < ((Number) o2).doubleValue();
398 } else if (mode == 0) {
399 return ((Number) o1).doubleValue() == ((Number) o2).doubleValue();
400 } else {
401 return ((Number) o1).doubleValue() > ((Number) o2).doubleValue();
402 }
403 } else {
404
405 if (mode == 0) {
406 return o1String.equals(o2String);
407 } else if (mode < 0) {
408 return o1String.compareTo(o2String) < 0;
409 } else {
410 return o1String.compareTo(o2String) > 0;
411 }
412 }
413 }
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429 public static Object inc(Object o) {
430 assert o != null;
431 double ans;
432 if (o instanceof Number) {
433 ans = ((Number) o).doubleValue() + 1;
434 } else {
435 try {
436 ans = Double.parseDouble(o.toString()) + 1;
437 } catch (NumberFormatException nfe) {
438 ans = 1;
439 }
440 }
441 if (isActuallyLong(ans)) {
442 return (long) Math.rint(ans);
443 } else {
444 return ans;
445 }
446 }
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462 public static Object dec(Object o) {
463 double ans;
464 if (o instanceof Number) {
465 ans = ((Number) o).doubleValue() - 1;
466 } else {
467 try {
468 ans = Double.parseDouble(o.toString()) - 1;
469 } catch (NumberFormatException nfe) {
470 ans = 1;
471 }
472 }
473 if (isActuallyLong(ans)) {
474 return (long) Math.rint(ans);
475 } else {
476 return ans;
477 }
478 }
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497 public final boolean toBoolean(Object o) {
498 boolean val;
499 if (o instanceof Integer) {
500 val = ((Integer) o).intValue() != 0;
501 } else if (o instanceof Long) {
502 val = ((Long) o).longValue() != 0;
503 } else if (o instanceof Double) {
504 val = ((Double) o).doubleValue() != 0;
505 } else if (o instanceof String) {
506 val = (o.toString().length() > 0);
507 } else if (o instanceof UninitializedObject) {
508 val = false;
509 } else if (o instanceof Pattern) {
510
511
512 Pattern pattern = (Pattern) o;
513 String s = inputLine == null ? "" : inputLine;
514 Matcher matcher = pattern.matcher(s);
515 val = matcher.find();
516 } else {
517 throw new Error("Unknown operand_stack type: " + o.getClass() + " for value " + o);
518 }
519 return val;
520 }
521
522
523
524
525
526
527
528
529
530
531
532
533 public static int split(Object array, Object string, String convfmt, Locale locale) {
534 return splitWorker(new StringTokenizer(toAwkString(string, convfmt, locale)), (AssocArray) array);
535 }
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551 public static int split(Object fs, Object array, Object string, String convfmt, Locale locale) {
552 String fsString = toAwkString(fs, convfmt, locale);
553 if (fsString.equals(" ")) {
554 return splitWorker(new StringTokenizer(toAwkString(string, convfmt, locale)), (AssocArray) array);
555 } else if (fsString.equals("")) {
556 return splitWorker(new CharacterTokenizer(toAwkString(string, convfmt, locale)), (AssocArray) array);
557 } else if (fsString.length() == 1) {
558 return splitWorker(
559 new SingleCharacterTokenizer(toAwkString(string, convfmt, locale), fsString.charAt(0)),
560 (AssocArray) array);
561 } else {
562 return splitWorker(new RegexTokenizer(toAwkString(string, convfmt, locale), fsString), (AssocArray) array);
563 }
564 }
565
566 private static int splitWorker(Enumeration<Object> e, AssocArray aa) {
567 int cnt = 0;
568 aa.clear();
569 while (e.hasMoreElements()) {
570 aa.put(++cnt, e.nextElement());
571 }
572 aa.put(0L, Integer.valueOf(cnt));
573 return cnt;
574 }
575
576
577
578
579
580
581
582
583 @SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "PartitioningReader is shared across callers")
584 public PartitioningReader getPartitioningReader() {
585 return partitioningReader;
586 }
587
588
589
590
591
592
593
594
595 public String getInputLine() {
596 return inputLine;
597 }
598
599
600
601
602
603
604
605
606 public void setInputLine(String inputLine) {
607 this.inputLine = inputLine;
608 }
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625 public boolean consumeInput(final InputStream input, boolean forGetline, Locale locale) throws IOException {
626 initializeArgList(locale);
627
628 while (true) {
629 if ((partitioningReader == null || inputLine == null)
630 && !prepareNextReader(input, locale)) {
631 return false;
632 }
633
634 inputLine = partitioningReader.readRecord();
635 if (inputLine == null) {
636 continue;
637 }
638
639 if (!forGetline) {
640
641 jrtParseFields();
642 }
643 vm.incNR();
644 if (partitioningReader.fromFilenameList()) {
645 vm.incFNR();
646 }
647 return true;
648 }
649 }
650
651
652
653
654
655
656 private void initializeArgList(Locale locale) {
657 if (arglistAa != null) {
658 return;
659 }
660 arglistAa = (AssocArray) vm.getARGV();
661 arglistIdx = 1;
662 hasFilenames = detectFilenames(locale);
663 }
664
665
666
667
668
669
670
671
672 private boolean detectFilenames(Locale locale) {
673 int argc = getArgCount();
674 for (long i = 1; i < argc; i++) {
675 if (arglistAa.isIn(i)) {
676 String arg = toAwkString(arglistAa.get(i), vm.getCONVFMT().toString(), locale);
677 if (arg.indexOf('=') == -1) {
678 return true;
679 }
680 }
681 }
682 return false;
683 }
684
685
686
687
688
689
690 private int getArgCount() {
691 return Math.toIntExact(toLong(vm.getARGC()));
692 }
693
694
695
696
697
698
699
700
701 private String nextArgument(Locale locale) {
702 int argc = getArgCount();
703 while (arglistIdx <= argc) {
704 Object o = arglistAa.get(arglistIdx++);
705 if (!(o instanceof UninitializedObject || o.toString().isEmpty())) {
706 return toAwkString(o, vm.getCONVFMT().toString(), locale);
707 }
708 }
709 return null;
710 }
711
712
713
714
715
716
717
718
719
720
721
722
723 private boolean prepareNextReader(InputStream input, Locale locale) throws IOException {
724 boolean ready = false;
725 while (!ready) {
726 String arg = nextArgument(locale);
727 if (arg == null) {
728 if (partitioningReader == null && !hasFilenames) {
729 partitioningReader = new PartitioningReader(
730 new InputStreamReader(input, StandardCharsets.UTF_8),
731 vm.getRS().toString());
732 vm.setFILENAME("");
733 return true;
734 }
735 return false;
736 }
737 if (arg.indexOf('=') != -1) {
738 setFilelistVariable(arg);
739 if (partitioningReader == null && !hasFilenames) {
740 partitioningReader = new PartitioningReader(
741 new InputStreamReader(input, StandardCharsets.UTF_8),
742 vm.getRS().toString());
743 vm.setFILENAME("");
744 return true;
745 }
746 if (partitioningReader != null) {
747 vm.incNR();
748 }
749 } else {
750 partitioningReader = new PartitioningReader(
751 new InputStreamReader(new FileInputStream(arg), StandardCharsets.UTF_8),
752 vm.getRS().toString(),
753 true);
754 vm.setFILENAME(arg);
755 vm.resetFNR();
756 ready = true;
757 }
758 }
759 return true;
760 }
761
762
763
764
765
766
767
768
769 public void setInputLineforEval(InputStream input) throws IOException {
770 partitioningReader = new PartitioningReader(
771 new InputStreamReader(input, StandardCharsets.UTF_8),
772 vm.getRS().toString());
773 inputLine = partitioningReader.readRecord();
774 if (inputLine != null) {
775 jrtParseFields();
776 vm.incNR();
777 }
778 }
779
780
781
782
783
784
785
786 private void setFilelistVariable(String nameValue) {
787 int eqIdx = nameValue.indexOf('=');
788
789 assert eqIdx >= 0;
790 if (eqIdx == 0) {
791 throw new IllegalArgumentException(
792 "Must have a non-blank variable name in a name=value variable assignment argument.");
793 }
794 String name = nameValue.substring(0, eqIdx);
795 String value = nameValue.substring(eqIdx + 1);
796 Object obj;
797 try {
798 obj = Integer.parseInt(value);
799 } catch (NumberFormatException nfe) {
800 try {
801 obj = Double.parseDouble(value);
802 } catch (NumberFormatException nfe2) {
803 obj = value;
804 }
805 }
806 vm.assignVariable(name, obj);
807 }
808
809
810
811
812
813 public void jrtParseFields() {
814 String fsString = vm.getFS().toString();
815 assert inputLine != null;
816
817 inputFields.clear();
818 inputFields.add(inputLine);
819
820 if (!inputLine.isEmpty()) {
821 Enumeration<Object> tokenizer;
822 if (fsString.equals(" ")) {
823 tokenizer = new StringTokenizer(inputLine);
824 } else if (fsString.length() == 1) {
825 tokenizer = new SingleCharacterTokenizer(inputLine, fsString.charAt(0));
826 } else if (fsString.equals("")) {
827 tokenizer = new CharacterTokenizer(inputLine);
828 } else {
829 tokenizer = new RegexTokenizer(inputLine, fsString);
830 }
831
832 while (tokenizer.hasMoreElements()) {
833 inputFields.add((String) tokenizer.nextElement());
834 }
835 }
836
837
838 recalculateNF();
839 }
840
841 private void recalculateNF() {
842 vm.setNF(Integer.valueOf(inputFields.size() - 1));
843 }
844
845
846
847
848 public boolean hasInputFields() {
849 return !inputFields.isEmpty();
850 }
851
852
853
854
855
856
857
858
859 public void jrtSetNF(Object nfObj) {
860 int nf = (int) toDouble(nfObj);
861 if (nf < 0) {
862 nf = 0;
863 }
864
865 int currentNF = inputFields.size() - 1;
866
867 if (nf < currentNF) {
868 for (int i = currentNF; i > nf; i--) {
869 inputFields.remove(i);
870 }
871 } else if (nf > currentNF) {
872 for (int i = currentNF + 1; i <= nf; i++) {
873 inputFields.add("");
874 }
875 }
876
877 rebuildDollarZeroFromFields();
878 }
879
880 private static int toFieldNumber(Object o) {
881 if (o instanceof Number) {
882 double num = ((Number) o).doubleValue();
883 if (num < 0) {
884 throw new RuntimeException("Field $(" + o.toString() + ") is incorrect.");
885 }
886 return (int) num;
887 }
888
889 String str = o.toString();
890 if (str.isEmpty()) {
891 return 0;
892 }
893
894 try {
895 double num = new BigDecimal(str).doubleValue();
896 if (num < 0) {
897 throw new RuntimeException("Field $(" + o.toString() + ") is incorrect.");
898 }
899 return (int) num;
900 } catch (NumberFormatException nfe) {
901 return 0;
902 }
903 }
904
905
906
907
908
909
910
911 public Object jrtGetInputField(Object fieldnumObj) {
912 return jrtGetInputField(toFieldNumber(fieldnumObj));
913 }
914
915
916
917
918
919
920
921
922
923 public Object jrtGetInputField(int fieldnum) {
924 if (fieldnum < inputFields.size()) {
925 String retval = inputFields.get(fieldnum);
926 assert retval != null;
927 return retval;
928 } else {
929 return BLANK;
930 }
931 }
932
933
934
935
936
937
938
939
940 public String jrtSetInputField(Object valueObj, int fieldNum) {
941 assert fieldNum >= 1;
942 assert valueObj != null;
943 String value = valueObj.toString();
944
945 if (valueObj instanceof UninitializedObject) {
946 if (fieldNum < inputFields.size()) {
947 inputFields.set(fieldNum, "");
948 }
949 } else {
950
951 for (int i = inputFields.size() - 1; i < fieldNum; i++) {
952 inputFields.add("");
953 }
954 inputFields.set(fieldNum, value);
955 }
956
957 rebuildDollarZeroFromFields();
958
959 recalculateNF();
960 return value;
961 }
962
963 private void rebuildDollarZeroFromFields() {
964 StringBuilder newDollarZeroSb = new StringBuilder();
965 String ofs = vm.getOFS().toString();
966 for (int i = 1; i < inputFields.size(); i++) {
967 if (i > 1) {
968 newDollarZeroSb.append(ofs);
969 }
970 newDollarZeroSb.append(inputFields.get(i));
971 }
972 inputFields.set(0, newDollarZeroSb.toString());
973 }
974
975
976
977
978
979
980
981
982
983 public Integer jrtConsumeFileInputForGetline(String filename) {
984 try {
985 if (jrtConsumeFileInput(filename)) {
986 return ONE;
987 } else {
988 jrtInputString = "";
989 return ZERO;
990 }
991 } catch (IOException ioe) {
992 jrtInputString = "";
993 return MINUS_ONE;
994 }
995 }
996
997
998
999
1000
1001
1002
1003
1004
1005 public Integer jrtConsumeCommandInputForGetline(String cmdString) {
1006 try {
1007 if (jrtConsumeCommandInput(cmdString)) {
1008 return ONE;
1009 } else {
1010 jrtInputString = "";
1011 return ZERO;
1012 }
1013 } catch (IOException ioe) {
1014 jrtInputString = "";
1015 return MINUS_ONE;
1016 }
1017 }
1018
1019
1020
1021
1022
1023
1024 public String jrtGetInputString() {
1025 return jrtInputString;
1026 }
1027
1028
1029
1030
1031
1032
1033
1034
1035 @SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "Callers modify the map of output files directly")
1036 public Map<String, PrintStream> getOutputFiles() {
1037 return outputFiles;
1038 }
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048 public PrintStream jrtGetPrintStream(String filename, boolean append) {
1049 PrintStream ps = outputFiles.get(filename);
1050 if (ps == null) {
1051 try {
1052 ps = new PrintStream(new FileOutputStream(filename, append), true, StandardCharsets.UTF_8.name());
1053
1054
1055 outputFiles.put(filename, ps);
1056 } catch (IOException ioe) {
1057 throw new AwkRuntimeException("Cannot open " + filename + " for writing: " + ioe);
1058 }
1059 }
1060 assert ps != null;
1061 return ps;
1062 }
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073 public boolean jrtConsumeFileInput(String filename) throws IOException {
1074 PartitioningReader pr = fileReaders.get(filename);
1075 if (pr == null) {
1076 try {
1077 pr = new PartitioningReader(
1078 new InputStreamReader(new FileInputStream(filename), StandardCharsets.UTF_8),
1079 vm.getRS().toString());
1080 fileReaders.put(filename, pr);
1081 vm.setFILENAME(filename);
1082 } catch (IOException ioe) {
1083 fileReaders.remove(filename);
1084 throw ioe;
1085 }
1086 }
1087
1088 inputLine = pr.readRecord();
1089 if (inputLine == null) {
1090 return false;
1091 } else {
1092 jrtInputString = inputLine;
1093 vm.incNR();
1094 return true;
1095 }
1096 }
1097
1098 private static Process spawnProcess(String cmd) throws IOException {
1099 Process p;
1100
1101 if (IS_WINDOWS) {
1102
1103 ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/c", cmd);
1104 p = pb.start();
1105 } else {
1106
1107 ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", cmd);
1108 p = pb.start();
1109 }
1110
1111 return p;
1112 }
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123 public boolean jrtConsumeCommandInput(String cmd) throws IOException {
1124 PartitioningReader pr = commandReaders.get(cmd);
1125 if (pr == null) {
1126 try {
1127 Process p = spawnProcess(cmd);
1128
1129 p.getOutputStream().close();
1130 DataPump.dump(cmd, p.getErrorStream(), System.err);
1131 commandProcesses.put(cmd, p);
1132 pr = new PartitioningReader(
1133 new InputStreamReader(p.getInputStream(), StandardCharsets.UTF_8),
1134 vm.getRS().toString());
1135 commandReaders.put(cmd, pr);
1136 vm.setFILENAME("");
1137 } catch (IOException ioe) {
1138 commandReaders.remove(cmd);
1139 Process p = commandProcesses.get(cmd);
1140 commandProcesses.remove(cmd);
1141 if (p != null) {
1142 p.destroy();
1143 }
1144 throw ioe;
1145 }
1146 }
1147
1148 inputLine = pr.readRecord();
1149 if (inputLine == null) {
1150 return false;
1151 } else {
1152 jrtInputString = inputLine;
1153 vm.incNR();
1154 return true;
1155 }
1156 }
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167 public PrintStream jrtSpawnForOutput(String cmd) {
1168 PrintStream ps = outputStreams.get(cmd);
1169 if (ps == null) {
1170 Process p;
1171 try {
1172 p = spawnProcess(cmd);
1173 DataPump.dump(cmd, p.getErrorStream(), error);
1174 DataPump.dump(cmd, p.getInputStream(), output);
1175 } catch (IOException ioe) {
1176 throw new AwkRuntimeException("Can't spawn " + cmd + ": " + ioe);
1177 }
1178 outputProcesses.put(cmd, p);
1179 try {
1180 ps = new PrintStream(p.getOutputStream(), true, StandardCharsets.UTF_8.name());
1181
1182 outputStreams.put(cmd, ps);
1183 } catch (java.io.UnsupportedEncodingException e) {
1184 throw new IllegalStateException(e);
1185 }
1186 }
1187 return ps;
1188 }
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205 public Integer jrtClose(String filename) {
1206 boolean b1 = jrtCloseFileReader(filename);
1207 boolean b2 = jrtCloseCommandReader(filename);
1208 boolean b3 = jrtCloseOutputFile(filename);
1209 boolean b4 = jrtCloseOutputStream(filename);
1210
1211 return (b1 || b2 || b3 || b4) ? ZERO : MINUS_ONE;
1212 }
1213
1214
1215
1216
1217
1218
1219 public void jrtCloseAll() {
1220 Set<String> set = new HashSet<String>();
1221 for (String s : fileReaders.keySet()) {
1222 set.add(s);
1223 }
1224 for (String s : commandReaders.keySet()) {
1225 set.add(s);
1226 }
1227 for (String s : outputFiles.keySet()) {
1228 set.add(s);
1229 }
1230 for (String s : outputStreams.keySet()) {
1231 set.add(s);
1232 }
1233 for (String s : set) {
1234 jrtClose(s);
1235 }
1236 }
1237
1238 private boolean jrtCloseOutputFile(String filename) {
1239 PrintStream ps = outputFiles.get(filename);
1240 if (ps != null) {
1241 ps.close();
1242 outputFiles.remove(filename);
1243 }
1244 return ps != null;
1245 }
1246
1247 private boolean jrtCloseOutputStream(String cmd) {
1248 Process p = outputProcesses.get(cmd);
1249 PrintStream ps = outputStreams.get(cmd);
1250 if (ps == null) {
1251 return false;
1252 }
1253 assert p != null;
1254 outputProcesses.remove(cmd);
1255 outputStreams.remove(cmd);
1256 ps.close();
1257 try {
1258
1259
1260 p.waitFor();
1261 p.exitValue();
1262 } catch (InterruptedException ie) {
1263 throw new AwkRuntimeException(
1264 "Caught exception while waiting for process exit: " + ie);
1265 }
1266 output.flush();
1267 error.flush();
1268 return true;
1269 }
1270
1271 private boolean jrtCloseFileReader(String filename) {
1272 PartitioningReader pr = fileReaders.get(filename);
1273 if (pr == null) {
1274 return false;
1275 }
1276 fileReaders.remove(filename);
1277 try {
1278 pr.close();
1279 return true;
1280 } catch (IOException ioe) {
1281 return false;
1282 }
1283 }
1284
1285 private boolean jrtCloseCommandReader(String cmd) {
1286 Process p = commandProcesses.get(cmd);
1287 PartitioningReader pr = commandReaders.get(cmd);
1288 if (pr == null) {
1289 return false;
1290 }
1291 assert p != null;
1292 commandReaders.remove(cmd);
1293 commandProcesses.remove(cmd);
1294 try {
1295 pr.close();
1296 try {
1297
1298
1299 p.waitFor();
1300 p.exitValue();
1301 } catch (InterruptedException ie) {
1302 throw new AwkRuntimeException(
1303 "Caught exception while waiting for process exit: " + ie);
1304 }
1305 output.flush();
1306 error.flush();
1307 return true;
1308 } catch (IOException ioe) {
1309 return false;
1310 }
1311 }
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326 public Integer jrtSystem(String cmd) {
1327 try {
1328 Process p = spawnProcess(cmd);
1329
1330 p.getOutputStream().close();
1331 DataPump.dump(cmd, p.getErrorStream(), error);
1332 DataPump.dump(cmd, p.getInputStream(), output);
1333 try {
1334 int retcode = p.waitFor();
1335 return Integer.valueOf(retcode);
1336 } catch (InterruptedException ie) {
1337 return Integer.valueOf(p.exitValue());
1338 }
1339 } catch (IOException ioe) {
1340 return MINUS_ONE;
1341 }
1342 }
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355 public static String sprintfNoCatch(Locale locale, String fmtArg, Object... arr) throws IllegalFormatException {
1356 return String.format(locale, fmtArg, arr);
1357 }
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368 public static void printfNoCatch(Locale locale, String fmtArg, Object... arr) {
1369 System.out.print(sprintfNoCatch(locale, fmtArg, arr));
1370 }
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382 public static void printfNoCatch(PrintStream ps, Locale locale, String fmtArg, Object... arr) {
1383 ps.print(sprintfNoCatch(locale, fmtArg, arr));
1384 }
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399 public static String prepareReplacement(String awkRepl) {
1400
1401 if (awkRepl == null) {
1402 return "";
1403 }
1404
1405
1406 if ((awkRepl.indexOf('\\') == -1) && (awkRepl.indexOf('$') == -1) && (awkRepl.indexOf('&') == -1)) {
1407 return awkRepl;
1408 }
1409
1410 StringBuilder javaRepl = new StringBuilder();
1411 for (int i = 0; i < awkRepl.length(); i++) {
1412 char c = awkRepl.charAt(i);
1413
1414
1415 if (c == '\\' && i < awkRepl.length() - 1) {
1416 i++;
1417 c = awkRepl.charAt(i);
1418 if (c == '&') {
1419 javaRepl.append('&');
1420 continue;
1421 } else if (c == '\\') {
1422 javaRepl.append("\\\\");
1423 continue;
1424 }
1425
1426
1427 javaRepl.append('\\');
1428 }
1429
1430 if (c == '$') {
1431 javaRepl.append("\\$");
1432 } else if (c == '&') {
1433 javaRepl.append("$0");
1434 } else {
1435 javaRepl.append(c);
1436 }
1437 }
1438
1439 return javaRepl.toString();
1440 }
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453 public static Integer replaceFirst(String origValue, String repl, String ere, StringBuffer sb) {
1454
1455 repl = prepareReplacement(repl);
1456
1457
1458 sb.setLength(0);
1459
1460 Pattern p = Pattern.compile(ere);
1461 Matcher m = p.matcher(origValue);
1462 int cnt = 0;
1463 if (m.find()) {
1464 ++cnt;
1465 m.appendReplacement(sb, repl);
1466 }
1467 m.appendTail(sb);
1468 return Integer.valueOf(cnt);
1469 }
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480 public static Integer replaceAll(String origValue, String repl, String ere, StringBuffer sb) {
1481
1482 sb.setLength(0);
1483
1484
1485 repl = prepareReplacement(repl);
1486
1487 Pattern p = Pattern.compile(ere);
1488 Matcher m = p.matcher(origValue);
1489 int cnt = 0;
1490 while (m.find()) {
1491 ++cnt;
1492 m.appendReplacement(sb, repl);
1493 }
1494 m.appendTail(sb);
1495 return Integer.valueOf(cnt);
1496 }
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507 public static String substr(Object startposObj, String str) {
1508 int startpos = (int) toDouble(startposObj);
1509 if (startpos <= 0) {
1510 throw new AwkRuntimeException("2nd arg to substr must be a positive integer");
1511 }
1512 if (startpos > str.length()) {
1513 return "";
1514 } else {
1515 return str.substring(startpos - 1);
1516 }
1517 }
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529 public static String substr(Object sizeObj, Object startposObj, String str) {
1530 int startpos = (int) toDouble(startposObj);
1531 if (startpos <= 0) {
1532 throw new AwkRuntimeException("2nd arg to substr must be a positive integer");
1533 }
1534 if (startpos > str.length()) {
1535 return "";
1536 }
1537 int size = (int) toDouble(sizeObj);
1538 if (size < 0) {
1539 throw new AwkRuntimeException("3nd arg to substr must be a non-negative integer");
1540 }
1541 if (startpos + size > str.length()) {
1542 return str.substring(startpos - 1);
1543 } else {
1544 return str.substring(startpos - 1, startpos + size - 1);
1545 }
1546 }
1547
1548
1549
1550
1551
1552
1553
1554
1555 public static int timeSeed() {
1556 long l = new Date().getTime();
1557 long l2 = l % (1000 * 60 * 60 * 24);
1558 int seed = (int) l2;
1559 return seed;
1560 }
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570 public static BSDRandom newRandom(int seed) {
1571 return new BSDRandom(seed);
1572 }
1573
1574
1575
1576
1577
1578
1579
1580
1581 public void applyRS(Object rsObj) {
1582
1583
1584 if (partitioningReader != null) {
1585 partitioningReader.setRecordSeparator(rsObj.toString());
1586 }
1587 }
1588 }