Merge: new option --define
authorJean Privat <jean@pryen.org>
Sat, 11 Oct 2014 12:24:15 +0000 (08:24 -0400)
committerJean Privat <jean@pryen.org>
Sat, 11 Oct 2014 12:24:15 +0000 (08:24 -0400)
It is standard in compiled programs to be able to setup some program configuration at compile-time.

Eg. C compilers accept a command-line option `-D` to define macros that will be used inside programs.
It is useful for configuring some string (like `-D PREFIX=/opt/nit/`, or `-D PORT=8081`) or activate some parts (conditional compilation, eg `-D WITH_SSL`).

This PR brings an equivalent capability to Nit engines through the new `-D` (`--define`) option.

The design behind the -D it to enable specific refinement of top-level functions at link-time.
Thus, basically

~~~sh
$ cat my_foo.nit
import foo
redef fun prefix do return "/opt/nit/"
$ nitg my_foo.nit
~~~

can be simplified into

~~~sh
$ nitg foo.nit -D prefix=/opt/nit/
~~~

Like `-m`, the `-D` creates a fictive module that refines the main module of the program.

`-D` also use the return type of the refined method to know how to interpret the text of the value.
Currently only Int, String and Bool is supported.

~~~nit
module foo
fun str: String do return "test"
fun num: Int do return 1
fun flag: Bool do return false
print str
print num
print flag
~~~

~~~sh
$ nitg foo.nit
$ ./foo
test
1
false
$ nitg foo.nit -D str=hello -D num=42 -D flag
$ ./foo
hello
42
true
~~~

The code of the PR is quite straightforward and show again that the new model is quite robust.

As usual, the first commits are some cleanup. The fun stuff is in the latter commits.

Pull-Request: #815
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>

16 files changed:
lib/console.nit
lib/standard/collection/abstract_collection.nit
lib/standard/file.nit
src/compiler/abstract_compiler.nit
src/interpreter/naive_interpreter.nit
src/rapid_type_analysis.nit
src/semantize/typing.nit
tests/base_for_finish.nit [new file with mode: 0644]
tests/sav/base_for_finish.res [new file with mode: 0644]
tests/sav/nitg-e/fixme/base_for_finish.res [new file with mode: 0644]
tests/sav/nitg-g/fixme/base_for_finish.res [new file with mode: 0644]
tests/sav/nitg-s/fixme/base_for_finish.res [new file with mode: 0644]
tests/sav/nitg-sg/fixme/base_for_finish.res [new file with mode: 0644]
tests/sav/test_for_abuse.res
tests/test_for_abuse.nit
tests/tests.sh

index e6a129f..d032886 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Simple numerical statistical analysis and presentation
+# Defines some ANSI Terminal Control Escape Sequences.
 module console
 
-# Redef String class to add a function to color the string
-redef class String
-       private fun add_escape_char(escapechar: String): String do
-               return "{escapechar}{self}{esc}[0m"
+# A ANSI/VT100 escape sequence.
+abstract class TermEscape
+       # The US-ASCII ESC character.
+       protected fun esc: Char do return 27.ascii
+end
+
+# ANSI/VT100 code to switch character attributes (SGR).
+#
+# By default, resets everything to the terminal’s defaults.
+#
+# Note:
+#
+# The escape sequence inserted at the end of the string by terminal-related
+# methods of `String` resets all character attributes to the terminal’s
+# defaults. So, when combining format `a` and `b`, something like
+# `("foo".a + " bar").b` will not work as expected, but `"foo".a.b + " bar".b`
+# will. You may also use `TermCharFormat` (this class).
+#
+# Usage example:
+#
+#     print "{(new TermCharFormat).yellow_fg.bold}a{(new TermCharFormat).yellow_fg}b{new TermCharFormat}"
+class TermCharFormat
+       super TermEscape
+
+       private var attributes: Array[String] = new Array[String]
+
+       # Copies the attributes from the specified format.
+       init from(format: TermCharFormat) do
+               attributes.add_all(format.attributes)
        end
 
-       private fun esc: Char do return 27.ascii
-       fun gray: String do return add_escape_char("{esc}[30m")
-       fun red: String do return add_escape_char("{esc}[31m")
-       fun green: String do return add_escape_char("{esc}[32m")
-       fun yellow: String do return add_escape_char("{esc}[33m")
-       fun blue: String do return add_escape_char("{esc}[34m")
-       fun purple: String do return add_escape_char("{esc}[35m")
-       fun cyan: String do return add_escape_char("{esc}[36m")
-       fun light_gray: String do return add_escape_char("{esc}[37m")
-       fun bold: String do return add_escape_char("{esc}[1m")
-       fun underline: String do return add_escape_char("{esc}[4m")
+       redef fun to_s: String do return "{esc}[{attributes.join(";")}m"
+
+       # Apply the specified SGR and return `self`.
+       private fun apply(sgr: String): TermCharFormat do
+               attributes.add(sgr)
+               return self
+       end
+
+       # Apply normal (default) format and return `self`.
+       fun default: TermCharFormat do return apply("0")
+
+       # Apply bold weight and return `self`.
+       fun bold: TermCharFormat do return apply("1")
+
+       # Apply underlining and return `self`.
+       fun underline: TermCharFormat do return apply("4")
+
+       # Apply blinking or bold weight and return `self`.
+       fun blink: TermCharFormat do return apply("5")
+
+       # Apply reverse video and return `self`.
+       fun inverse: TermCharFormat do return apply("7")
+
+       # Apply normal weight and return `self`.
+       fun normalWeight: TermCharFormat do return apply("22")
+
+       # Add the attribute that disable inderlining and return `self`.
+       fun not_underlined: TermCharFormat do return apply("24")
+
+       # Add the attribute that disable blinking and return `self`.
+       fun steady: TermCharFormat do return apply("25")
+
+       # Add the attribute that disable reverse video and return `self`.
+       fun positive: TermCharFormat do return apply("27")
+
+       # Apply a black foreground and return `self`.
+       fun black_fg: TermCharFormat do return apply("30")
+
+       # Apply a red foreground and return `self`.
+       fun red_fg: TermCharFormat do return apply("31")
+
+       # Apply a green foreground and return `self`.
+       fun green_fg: TermCharFormat do return apply("32")
+
+       # Apply a yellow foreground and return `self`.
+       fun yellow_fg: TermCharFormat do return apply("33")
+
+       # Apply a blue foreground and return `self`.
+       fun blue_fg: TermCharFormat do return apply("34")
+
+       # Apply a mangenta foreground and return `self`.
+       fun magenta_fg: TermCharFormat do return apply("35")
+
+       # Apply a cyan foreground and return `self`.
+       fun cyan_fg: TermCharFormat do return apply("36")
+
+       # Apply a white foreground and return `self`.
+       fun white_fg: TermCharFormat do return apply("37")
+
+       # Apply the default foreground and return `self`.
+       fun default_fg: TermCharFormat do return apply("39")
+
+       # Apply a black backgroud and return `self`.
+       fun black_bg: TermCharFormat do return apply("40")
+
+       # Apply a red backgroud and return `self`.
+       fun red_bg: TermCharFormat do return apply("41")
+
+       # Apply a green backgroud and return `self`.
+       fun green_bg: TermCharFormat do return apply("42")
+
+       # Apply a yellow backgroud and return `self`.
+       fun yellow_bg: TermCharFormat do return apply("43")
+
+       # Apply a blue backgroud and return `self`.
+       fun blue_bg: TermCharFormat do return apply("44")
+
+       # Apply a mangenta backgroud and return `self`.
+       fun magenta_bg: TermCharFormat do return apply("45")
+
+       # Apply a cyan backgroud and return `self`.
+       fun cyan_bg: TermCharFormat do return apply("46")
+
+       # Apply a white backgroud and return `self`.
+       fun white_bg: TermCharFormat do return apply("47")
+
+       # Apply the default backgroud and return `self`.
+       fun default_bg: TermCharFormat do return apply("49")
 end
 
+# Redefine the `String` class to add functions to color the string.
+redef class String
+       private fun apply_format(f: TermCharFormat): String do
+               return "{f}{self}{normal}"
+       end
+
+       private fun normal: TermCharFormat do return new TermCharFormat
+
+       # Make the text appear in dark gray (or black) in a ANSI/VT100 terminal.
+       #
+       # WARNING: SEE: `TermCharFormat`
+       fun gray: String do return apply_format(normal.black_fg)
+
+       # Make the text appear in red in a ANSI/VT100 terminal.
+       #
+       # WARNING: SEE: `TermCharFormat`
+       fun red: String do return apply_format(normal.red_fg)
+
+       # Make the text appear in green in a ANSI/VT100 terminal.
+       #
+       # WARNING: SEE: `TermCharFormat`
+       fun green: String do return apply_format(normal.green_fg)
+
+       # Make the text appear in yellow in a ANSI/VT100 terminal.
+       #
+       # WARNING: SEE: `TermCharFormat`
+       fun yellow: String do return apply_format(normal.yellow_fg)
+
+       # Make the text appear in blue in a ANSI/VT100 terminal.
+       #
+       # WARNING: SEE: `TermCharFormat`
+       fun blue: String do return apply_format(normal.blue_fg)
+
+       # Make the text appear in mangenta in a ANSI/VT100 terminal.
+       #
+       # WARNING: SEE: `TermCharFormat`
+       fun purple: String do return apply_format(normal.magenta_fg)
+
+       # Make the text appear in cyan in a ANSI/VT100 terminal.
+       #
+       # WARNING: SEE: `TermCharFormat`
+       fun cyan: String do return apply_format(normal.cyan_fg)
+
+       # Make the text appear in light gray (or white) in a ANSI/VT100 terminal.
+       #
+       # WARNING: SEE: `TermCharFormat`
+       fun light_gray: String do return apply_format(normal.white_fg)
+
+       # Make the text appear in bold in a ANSI/VT100 terminal.
+       #
+       # WARNING: SEE: `TermCharFormat`
+       fun bold: String do return apply_format(normal.bold)
+
+       # Make the text underlined in a ANSI/VT100 terminal.
+       #
+       # WARNING: SEE: `TermCharFormat`
+       fun underline: String do return apply_format(normal.underline)
+end
index d2cdb2c..843f8eb 100644 (file)
@@ -152,6 +152,16 @@ interface Iterator[E]
 
        # Iterate over `self`
        fun iterator: Iterator[E] do return self
+
+       # Post-iteration hook.
+       #
+       # Used to inform `self` that the iteration is over.
+       # Specific iterators can use this to free some resources.
+       #
+       # Is automatically invoked at the end of `for` structures.
+       #
+       # Do nothing by default.
+       fun finish do end
 end
 
 # A collection that contains only one item.
@@ -526,6 +536,16 @@ interface MapIterator[K: Object, V]
 
        # Set a new `item` at `key`.
        #fun item=(item: E) is abstract
+
+       # Post-iteration hook.
+       #
+       # Used to inform `self` that the iteration is over.
+       # Specific iterators can use this to free some resources.
+       #
+       # Is automatically invoked at the end of `for` structures.
+       #
+       # Do nothing by default.
+       fun finish do end
 end
 
 # Iterator on a 'keys' point of view of a map
index 58fb382..b8f5bab 100644 (file)
@@ -65,6 +65,7 @@ class IFStream
        redef fun close
        do
                var i = _file.io_close
+               _buffer.clear
                end_reached = true
        end
 
index b9987c0..04e0719 100644 (file)
@@ -2641,6 +2641,12 @@ redef class AForExpr
                v.compile_callsite(next_meth, [it])
                v.add("\}")
                v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
+
+               var method_finish = self.method_finish
+               if method_finish != null then
+                       # TODO: Find a way to call this also in long escape (e.g. return)
+                       v.compile_callsite(method_finish, [it])
+               end
        end
 end
 
index 01c872d..55c6567 100644 (file)
@@ -1357,7 +1357,7 @@ redef class AForExpr
                #self.debug("iter {iter}")
                loop
                        var isok = v.callsite(method_is_ok, [iter]).as(not null)
-                       if not isok.is_true then return
+                       if not isok.is_true then break
                        if self.variables.length == 1 then
                                var item = v.callsite(method_item, [iter]).as(not null)
                                #self.debug("item {item}")
@@ -1371,11 +1371,15 @@ redef class AForExpr
                                abort
                        end
                        v.stmt(self.n_block)
-                       if v.is_break(self.escapemark) then return
+                       if v.is_break(self.escapemark) then break
                        v.is_continue(self.escapemark) # Clear the break
-                       if v.is_escaping then return
+                       if v.is_escaping then break
                        v.callsite(method_next, [iter])
                end
+               var method_finish = self.method_finish
+               if method_finish != null then
+                       v.callsite(method_finish, [iter])
+               end
        end
 end
 
index 7cbdaf9..897d7b7 100644 (file)
@@ -678,6 +678,8 @@ redef class AForExpr
                        abort
                end
                v.add_callsite(self.method_next)
+               var mf = self.method_finish
+               if mf != null then v.add_callsite(mf)
        end
 end
 
index 25fa0d6..cf84e4c 100644 (file)
@@ -304,6 +304,15 @@ private class TypeVisitor
                return callsite
        end
 
+       fun try_get_method(node: ANode, recvtype: MType, name: String, recv_is_self: Bool): nullable CallSite
+       do
+               var unsafe_type = self.anchor_to(recvtype)
+               var mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name)
+               if mproperty == null then return null
+               return get_method(node, recvtype, name, recv_is_self)
+       end
+
+
        # Visit the expressions of args and check their conformity with the corresponding type in signature
        # The point of this method is to handle varargs correctly
        # Note: The signature must be correctly adapted
@@ -846,6 +855,7 @@ redef class AForExpr
        var method_item: nullable CallSite
        var method_next: nullable CallSite
        var method_key: nullable CallSite
+       var method_finish: nullable CallSite
 
        private fun do_type_iterator(v: TypeVisitor, mtype: MType)
        do
@@ -937,6 +947,8 @@ redef class AForExpr
                end
                self.method_next = nextdef
 
+               self.method_finish = v.try_get_method(self, ittype, "finish", false)
+
                if is_map then
                        var keydef = v.get_method(self, ittype, "key", false)
                        if keydef == null then
diff --git a/tests/base_for_finish.nit b/tests/base_for_finish.nit
new file mode 100644 (file)
index 0000000..baaf29e
--- /dev/null
@@ -0,0 +1,60 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import array
+
+class MyC
+       var data: Collection[Object]
+       fun iterator: MyI do return new MyI(data.iterator)
+end
+
+class MyI
+       super Iterator[Object]
+       var iter: Iterator[Object]
+       redef fun is_ok do return iter.is_ok
+       redef fun item do return iter.item
+       redef fun next do iter.next
+       redef fun finish do 0.output
+end
+
+fun test(a: MyC)
+do
+       for x in a do
+               x.output
+               for y in [10,20] do
+                       y.output
+                       if x == 2 then return
+               end
+               100.output
+       end
+       200.output
+end
+
+var a = new MyC([1,2,3])
+
+for x in a do
+       x.output
+end
+
+'\n'.output
+
+for x in a do
+       x.output
+       if x == 2 then break
+       100.output
+end
+
+'\n'.output
+
+test(a)
diff --git a/tests/sav/base_for_finish.res b/tests/sav/base_for_finish.res
new file mode 100644 (file)
index 0000000..07ea0b2
--- /dev/null
@@ -0,0 +1,17 @@
+1
+2
+3
+0
+
+1
+100
+2
+0
+
+1
+10
+20
+100
+2
+10
+0
diff --git a/tests/sav/nitg-e/fixme/base_for_finish.res b/tests/sav/nitg-e/fixme/base_for_finish.res
new file mode 100644 (file)
index 0000000..390c4e4
--- /dev/null
@@ -0,0 +1,16 @@
+1
+2
+3
+0
+
+1
+100
+2
+0
+
+1
+10
+20
+100
+2
+10
diff --git a/tests/sav/nitg-g/fixme/base_for_finish.res b/tests/sav/nitg-g/fixme/base_for_finish.res
new file mode 100644 (file)
index 0000000..390c4e4
--- /dev/null
@@ -0,0 +1,16 @@
+1
+2
+3
+0
+
+1
+100
+2
+0
+
+1
+10
+20
+100
+2
+10
diff --git a/tests/sav/nitg-s/fixme/base_for_finish.res b/tests/sav/nitg-s/fixme/base_for_finish.res
new file mode 100644 (file)
index 0000000..390c4e4
--- /dev/null
@@ -0,0 +1,16 @@
+1
+2
+3
+0
+
+1
+100
+2
+0
+
+1
+10
+20
+100
+2
+10
diff --git a/tests/sav/nitg-sg/fixme/base_for_finish.res b/tests/sav/nitg-sg/fixme/base_for_finish.res
new file mode 100644 (file)
index 0000000..390c4e4
--- /dev/null
@@ -0,0 +1,16 @@
+1
+2
+3
+0
+
+1
+100
+2
+0
+
+1
+10
+20
+100
+2
+10
index 51ef296..f2856be 100644 (file)
@@ -1 +1,4 @@
 # This file is part of NIT ( http://www.nitlanguage.org ).
+f is closed? false
+f is closed? true
+* ** **** *******
index 545440b..cae1cd1 100644 (file)
 
 import for_abuse
 
+var escape_f: nullable IStream = null
 for f in file_open("test_for_abuse.nit") do
+       escape_f = f
        print f.read_line
+       print "f is closed? {f.eof}"
 end
+print "f is closed? {escape_f.eof}"
 
 var array = ["*", "****", "**", "*******"]
 for q in array.sort_fa do
-       q.res = q.b.length <=> q.b.length
+       # IN:
+       #     q.a
+       #     q-b
+       # OUT
+       #     q.res
+       q.res = q.a.length <=> q.b.length
 end
-
+print array.join(" ")
index c0965b3..14be6d4 100755 (executable)
@@ -55,6 +55,68 @@ Usage: $e [options] modulenames
 END
 }
 
+# Run a command with a timeout and a time count.
+# Options:
+#   -o file    write the user time into file (REQUIRED). see `-o` in `man time`
+#   -a         append the time to the file (instead of overwriting it). see `-a` in `man time`
+saferun()
+{
+       local stop=false
+       local o=
+       local a=
+       while [ $stop = false ]; do
+               case $1 in
+                       -o) o="$2"; shift; shift;;
+                       -a) a="-a"; shift;;
+                       *) stop=true
+               esac
+       done
+       if test -n "$TIME"; then
+               $TIME -o "$o" $a $TIMEOUT "$@"
+       else
+               $TIMEOUT "$@"
+               if test -n "$a"; then echo 0 >> "$o"; else echo 0 > "$o"; fi
+       fi
+}
+
+# Output a timestamp attribute for XML, or an empty line
+timestamp()
+{
+       if test -n "$TIMESTAMP"; then
+               echo "timestamp='`$TIMESTAMP`'"
+       else
+               echo ""
+       fi
+
+}
+
+# Get platform specific commands ##########################
+
+# Detect a working timeout
+if sh -c "timelimit echo" 1>/dev/null 2>&1; then
+       TIMEOUT="timelimit -t 600"
+elif sh -c "timeout 1 echo" 1>/dev/null 2>&1; then
+       TIMEOUT="timeout 600s"
+else
+       echo "No timelimit or timeout command detected. Tests may hang :("
+fi
+
+# Detect a working time command
+if env time --quiet -f%U true 2>/dev/null; then
+       TIME="env time --quiet -f%U"
+elif env time -f%U true 2>/dev/null; then
+       TIME="env time -f%U"
+else
+       TIME=
+fi
+
+# Detect a working date command
+if date -Iseconds >/dev/null 2>&1; then
+       TIMESTAMP="date -Iseconds"
+else
+       TIMESTAMP=
+fi
+
 # $1 is the pattern of the test
 # $2 is the file to compare to
 # the result is:
@@ -102,7 +164,7 @@ function process_result()
        OLD=""
        LIST=""
        FIRST=""
-       echo >>$xml "<testcase classname='$pack' name='$description' time='`cat $outdir/$pattern.time.out`' timestamp='`date -Iseconds`'>"
+       echo >>$xml "<testcase classname='$pack' name='$description' time='`cat $outdir/$pattern.time.out`' `timestamp`>"
        #for sav in "sav/$engine/fixme/$pattern.res" "sav/$engine/$pattern.res" "sav/fixme/$pattern.res" "sav/$pattern.res" "sav/$pattern.sav"; do
        for savdir in $savdirs; do
                sav=$savdir/fixme/$pattern.res
@@ -241,12 +303,12 @@ need_skip()
        test "$noskip" = true && return 1
        if echo "$1" | grep -f "$engine.skip" >/dev/null 2>&1; then
                echo "=> $2: [skip]"
-               echo >>$xml "<testcase classname='$3' name='$2' timestamp='`date -Iseconds`'><skipped/></testcase>"
+               echo >>$xml "<testcase classname='$3' name='$2' `timestamp`><skipped/></testcase>"
                return 0
        fi
        if test -n "$isinterpret" && echo "$1" | grep -f "exec.skip" >/dev/null 2>&1; then
                echo "=> $2: [skip exec]"
-               echo >>$xml "<testcase classname='$3' name='$2' timestamp='`date -Iseconds`'><skipped/></testcase>"
+               echo >>$xml "<testcase classname='$3' name='$2' `timestamp`><skipped/></testcase>"
                return 0
        fi
        return 1
@@ -363,14 +425,6 @@ savdirs="sav/$engine $savdirs sav/"
 # Set NIT_DIR if needed
 [ -z "$NIT_DIR" ] && export NIT_DIR=..
 
-if sh -c "timelimit echo" 1>/dev/null 2>&1; then
-       TIMEOUT="timelimit -t 600"
-elif sh -c "timeout 1 echo" 1>/dev/null 2>&1; then
-       TIMEOUT="timeout 600s"
-else
-       echo "No timelimit or timeout command detected. Tests may hang :("
-fi
-
 # Mark to distinguish files among tests
 # MARK=
 
@@ -470,7 +524,7 @@ END
                                echo $NITC --no-color $OPT -o "$ffout" "$i" "$includes" $nocc
                        fi
                        NIT_NO_STACK=1 JNI_LIB_PATH=$JNI_LIB_PATH JAVA_HOME=$JAVA_HOME \
-                               /usr/bin/time -f%U -o "$ff.time.out" $TIMEOUT $NITC --no-color $OPT -o "$ffout" "$i" $includes $nocc 2> "$ff.cmp.err" > "$ff.compile.log"
+                               saferun -o "$ff.time.out" $NITC --no-color $OPT -o "$ffout" "$i" $includes $nocc 2> "$ff.cmp.err" > "$ff.compile.log"
                        ERR=$?
                        if [ "x$verbose" = "xtrue" ]; then
                                cat "$ff.compile.log"
@@ -482,7 +536,7 @@ END
                        chmod +x "$ff.bin"
                        if grep "Fatal Error: more than one primitive class" "$ff.compile.log" > /dev/null; then
                                echo " [skip] do no not imports kernel"
-                               echo >>$xml "<testcase classname='$pack' name='$bf' timestamp='`date -Iseconds`'><skipped/></testcase>"
+                               echo >>$xml "<testcase classname='$pack' name='$bf' `timestamp`><skipped/></testcase>"
                                continue
                        fi
                fi
@@ -510,7 +564,7 @@ END
                                echo "NIT_NO_STACK=1 $ff.bin" $args
                        fi
                        NIT_NO_STACK=1 LD_LIBRARY_PATH=$JNI_LIB_PATH \
-                               /usr/bin/time -f%U -a -o "$ff.time.out" $TIMEOUT "$ff.bin" $args < "$inputs" > "$ff.res" 2>"$ff.err"
+                               saferun -a -o "$ff.time.out" "$ff.bin" $args < "$inputs" > "$ff.res" 2>"$ff.err"
                        mv $ff.time.out $ff.times.out
                        awk '{ SUM += $1} END { print SUM }' $ff.times.out > $ff.time.out
 
@@ -555,7 +609,7 @@ END
                                        echo -n "==> $name "
                                        echo "$ff.bin $args" > "$fff.bin"
                                        chmod +x "$fff.bin"
-                                       WRITE="$fff.write" /usr/bin/time -f%U -o "$fff.time.out" sh -c "NIT_NO_STACK=1 $TIMEOUT $fff.bin < $ffinputs > $fff.res 2>$fff.err"
+                                       WRITE="$fff.write" saferun -o "$fff.time.out" sh -c "NIT_NO_STACK=1 $fff.bin < $ffinputs > $fff.res 2>$fff.err"
                                        if [ "x$verbose" = "xtrue" ]; then
                                                cat "$fff.res"
                                                cat >&2 "$fff.err"