@@ -93,6 +93,47 @@ public static Value ioExec(final Value parameter) throws IOException, Interrupte
9393 return new RecordValue (EXEC_NAMES , new Value [] {exitCode , stdout , stderr }, false );
9494 }
9595
96+ @ TLAPlusOperator (identifier = "IOExecTemplate" , module = "IOUtils" , minLevel = 1 , warn = false )
97+ public static Value ioExecTemplate (final Value commandTemplate , final Value parameter ) throws IOException , InterruptedException {
98+ // 1. Check parameters and covert.
99+ if (!(commandTemplate instanceof StringValue )) {
100+ throw new EvalException (EC .TLC_MODULE_ONE_ARGUMENT_ERROR ,
101+ new String [] { "IOExec" , "string" , Values .ppr (commandTemplate .toString ()) });
102+ }
103+ if (!(parameter instanceof TupleValue )) {
104+ throw new EvalException (EC .TLC_MODULE_ONE_ARGUMENT_ERROR ,
105+ new String [] { "IOExec" , "sequence" , Values .ppr (parameter .toString ()) });
106+ }
107+ final StringValue sv = (StringValue ) commandTemplate ;
108+ final TupleValue tv = (TupleValue ) parameter ;
109+
110+ // 2. Build actual command-line by merging command and parameter.
111+ // XXX does not support multiple %s inside a template part
112+ final String [] command = sv .val .toString ().split ("\\ s+" );
113+ int j = 0 ;
114+ for (int i = 0 ; i < command .length ; ++i ) {
115+ if (command [i ].contains ("%s" )) {
116+ if (j < tv .elems .length ) {
117+ command [i ] = String .format (command [i ], ((StringValue ) tv .elems [j ++]).val .toString ());
118+ } else {
119+ // Too many %s
120+ // XXX throw proper exception
121+ throw new EvalException (EC .TLC_MODULE_ONE_ARGUMENT_ERROR ,
122+ new String [] { "IOExec" , "sequence" , Values .ppr (parameter .toString ()) });
123+ }
124+ }
125+ }
126+
127+ // 3. Run command-line and receive its output.
128+ final Process process = new ProcessBuilder (command )/*.inheritIO()*/ .start ();
129+
130+ final StringValue stdout = new StringValue (new String (process .getInputStream ().readAllBytes ()));
131+ final StringValue stderr = new StringValue (new String (process .getErrorStream ().readAllBytes ()));
132+ final IntValue exitCode = IntValue .gen (process .waitFor ());
133+
134+ return new RecordValue (EXEC_NAMES , new Value [] {exitCode , stdout , stderr }, false );
135+ }
136+
96137 private static String convert (IValue v ) {
97138 if (! (v instanceof StringValue )) {
98139 // XXX Proper exception
0 commit comments