Hi Rob and all,

I've been playing around with 'tac'. And as a result you can find two patches in attach. The first one removes some code from tac for that simple reason that the tac toy contains some logic (including a strlen) to remove a trailing \n (if present). But this \n is the seperator which get_line() internally passes to get_rawline() and that newline is already removed in get_line().

Next to this you can find some test for tac which are based upon the cat tests. I have however found two problems I'd like to throw in the group.

Problem 1:
On my system:
edb@lapedb:~/today$ echo -ne "abc\ndef" | tac
defabc\n
tac in toybox:
edb@lapedb:~/edb-stuff/toybox/toybox$ echo -ne "abc\ndef" | ./toybox tac
def\n
abc\n
(I added the \n here for visibility). This however cannot be trivially fixed because of the implicit separator in get_line() as stated above. Nevertheless the output of the 'default' tac is such a corner case that probably no sane human being would use it that way (I hope).

Problem 2:
cat has a test which writes to /dev/full to see if the error gets caught. cat however doesn't use xwrite but uses xputs to put its output (also a cause for problem 1). But take a look at the following strace output of

echo "boe" | strace ./toybox tac > /dev/full

read(0, "b", 1)                         = 1
read(0, "o", 1)                         = 1
read(0, "e", 1)                         = 1
read(0, "\n", 1)                        = 1
read(0, "", 1)                          = 0
fstat64(1, {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 7), ...}) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, 0xbfb6ae50) = -1 ENOTTY (Inappropriate ioctl for device) mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb773d000 write(1, "boe\n", 4) = -1 ENOSPC (No space left on device)
exit_group(0)                           = ?

True, xputs uses puts which ends up calling write() which returns -1 but this does not ripple through to puts() and thus the error condition in xputs() doesn't trigger (it just happily return a '4').

So in order to fix the issues above I would make 'tac' more like 'cat', which would probably mean not using get_line() but using get_rawline() (and thus reintroducing what I threw out in my patch ;-) ), not removing the newline and using xwrite() (eventually storing the length somewhere) to write the output. This would still not solve the root problem of xputs() not triggering when write throws and ENOSPC at you.

What do you guys think ?

(Btw, my patch containing the tests, has the /dev/full test commented out, and the abc\ndef case modeled as the current toybox behavior).

gr
E.



--
Elie De Brauwer

# HG changeset patch
# User Elie De Brauwer <[email protected]>
# Date 1355596109 -3600
# Node ID baad52aa98b3575cbea6dec172ff8f5f5a137cb7
# Parent  8947c0d35e585013640bac885a01d2c63b0a1b19
Simplify tac, the newline checking is already done in the get_line() function

diff -r 8947c0d35e58 -r baad52aa98b3 toys/other/tac.c
--- a/toys/other/tac.c	Wed Dec 12 21:13:12 2012 -0600
+++ b/toys/other/tac.c	Sat Dec 15 19:28:29 2012 +0100
@@ -23,12 +23,9 @@
   // Read in lines
   for (;;) {
     struct arg_list *temp;
-    int len;
 
     if (!(c = get_line(fd))) break;
 
-    len = strlen(c);
-    if (len && c[len-1]=='\n') c[len-1] = 0;
     temp = xmalloc(sizeof(struct arg_list));
     temp->next = list;
     temp->arg = c;
# HG changeset patch
# User Elie De Brauwer <[email protected]>
# Date 1355597503 -3600
# Node ID 4bccd66ab0daccacd902821f97e8f8bbf4ff6ef9
# Parent  baad52aa98b3575cbea6dec172ff8f5f5a137cb7
Adding tests for tac based on cat tests

diff -r baad52aa98b3 -r 4bccd66ab0da scripts/test/tac.test
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/test/tac.test	Sat Dec 15 19:51:43 2012 +0100
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+
+echo -e "one-A\none-B" > file1 
+echo -e "two-A\ntwo-B" > file2
+testing "tac" "tac && echo yes" "one-B\none-A\nyes\n" "" "one-A\none-B\n"
+testing "tac -" "tac - && echo yes" "one-B\none-A\nyes\n" "" "one-A\none-B\n"
+testing "tac file1 file2" "tac file1 file2" "one-B\none-A\ntwo-B\ntwo-A\n"  "" ""
+testing "tac - file"      "tac - file1"     "zero-B\nzero-A\none-B\none-A\n" "" "zero-A\nzero-B\n"
+testing "tac file -"      "tac file1 -"     "one-B\none-A\nzero-B\nzero-A\n" "" "zero-A\nzero-B\n"
+
+testing "tac file1 notfound file2" \
+        "tac file1 notfound file2 2>stderr && echo ok ; tac stderr; rm stderr" \
+        "one-B\none-A\ntwo-B\ntwo-A\ntac: notfound: No such file or directory\n" "" ""
+
+# echo -ne "abc\ndef" | tac actually gives "defabc\n"
+testing "tac no trailing newline" "tac -" "def\nabc\n" "" "abc\ndef"
+
+# xputs used by tac does not propagate this error condition properly. 
+#testing "tac > /dev/full" \
+#        "tac - > /dev/full 2>stderr && echo ok; cat stderr; rm stderr" \
+#        "tac: write: No space left on device\n" "" "zero\n"
+
+# 
+
+rm file1 file2
\ No newline at end of file
_______________________________________________
Toybox mailing list
[email protected]
http://lists.landley.net/listinfo.cgi/toybox-landley.net

Reply via email to