[Toybox] [CLEANUP] eject commit 947

Rob Landley rob at landley.net
Thu Jul 11 22:11:19 PDT 2013


Eject cleanups in commit 947

   http://landley.net/hg/toybox/rev/947

To start with, this isn't just "not in susv4", it isn't in LSB 4.1  
either. So say "no standard".

The usage message: collate the option flags into one [-block]. The  
square brackets mean something is optional, an eplipsis (...) means  
something can be repeated an arbitrary number of times (this is more or  
less copied from man pages), but the device argument can occur zero or  
one times, so [DEVICE] is the way to say that. Use one tab instead of  
spaces between the option and its description. (This is how the others  
do it, saves a couple bytes.)

The #defines are essentially comments: the magic constant is here in  
the C file anyway, it might as well be at the call site with a comment  
about the macro name the constant stands for. Note that DRIVE_NOT_READY  
was never used.


--- remove_scsi():

for one line comments I tend to use // instead of /* */ because c99  
allows it. The int argument is a file descriptor so it's standard to  
say "fd" for that. (If you see "fd" you generally know what it is, just  
like i is probably a loop counter.)

I generally have variable declarations as a single block at the start  
of a function, separated from non-declaration statements by a space.  
This had two blocks with a space between them, so collate. While I'm at  
it: we have "toybuf" so declaring structs and arrays on the stack isn't  
really necessary, use chunks of toybuf instead. (The reason I did  
toybuf+64 instead of toybuf+sizeof(blah) is I dunno what the alignment  
of the struct is, or what alignment considerations the buffers have.  
This way everything's 32-byte aligned.

Using toybuf means the memset() can go away: is starts zeroed. I  
renamed in_out_header to just "header" because it's a local variable  
and the smaller the scope the simpler the name you can get away with.

Ripped out the ioctl() querying the version, on the theory A) we don't  
really support old pre-2.0 kernels anyway, B) the failure is to exit  
without ejecting, which is pretty much the failure if we did run on  
such an old kernel somehow. (We wouldn't compile against its libc, but  
oh well.)

--- eject_main():

Move rc declaration into the else {} block that actually uses it, and  
don't bother initializing it to 0 since the only use starts with an  
unconditional assignment.

Move "/dev/cdrom" assignment into variable declaration, and then  
conditionally assign to it if we have an argument. (Not only is this  
one fewer line of code, but the compiler can turn the if () into a  
conditional assignment avoiding a jump and corresponding branch  
prediction, and it's the same amount of assignment code either way so  
the binary isn't any larger.) Put a space between variable declarations  
and non-declaration code. And have the test the same thing we're  
assigning instead of a different variable so we load into a register  
and then re-use that register. (The command line argument array is null  
terminated so toys.optargs[toys.optc] is guaranteed to be NULL the same  
way argv[argc] is guaranteed to be NULL. I don't remember if that's the  
C standard, posix, or the ELF spec, but I tracked down where it was  
standardized once and it is, not just "happens to be true" but  
required.)

The above #defines substitued in as constants start kicking in here,  
not the comments at end of line. The if (TRAY_OPEN) ioctl(EJECT) stuff  
could be on one line, but they're on two lines so each line can have a  
trailing comment with the symbol name that should theoretically be in  
some header somewhere, but isn't.

Inserted extra parentheses:

-    if (toys.optflags & FLAG_T || toys.optflags & FLAG_t) {
+    if ((toys.optflags & FLAG_T) || (toys.optflags & FLAG_t)) {

-      if (toys.optflags & FLAG_t || rc == 2) //CDS_TRAY_OPEN = 2
+      if ((toys.optflags & FLAG_t) || rc == 2)         // CDS_TRAY_OPEN

Mixing logical and boolean operators, the precedence is nonobvious.  
Dennis Ritchie wrote about the historical reasons in his History of  
Programming Languages conference talk:

   http://cm.bell-labs.com/cm/cs/who/dmr/chist.html

Relevant chunk:

> At the suggestion of Alan Snyder, I introduced the && and || operators
> to make the mechanism more explicit. Their tardy introduction explains
> an infelicity of C's precedence rules. In B one writes
> 
>   if (a==b & c) ...
> 
> to check whether a equals b and c is non-zero; in such a conditional
> expression it is better that & have lower precedence than ==. In
> converting from B to C, one wants to replace & by && in such a  
> statement;
> to make the conversion less painful, we decided to keep the precedence
> of the & operator the same relative to ==, and merely split the
> precedence of && slightly from &. Today, it seems that it would have
> been preferable to move the relative precedences of & and ==, and  
> thereby
> simplify a common C idiom: to test a masked value against another  
> value,
> one must write
> 
>   if ((a&mask) == b) ...
> 
> where the inner parentheses are required but easily forgotten.

And this means whenever I have a boolean operation mixed with logical  
operators, I parenthesize even when it's not strictly required.

The trailing comments are off to the right a bit because there's  
several of them so lining them up helps readability.

The close isn't strictly required, so I put it in CFG_TOYBOX_FREE which  
is basically the "I'm going to run this under valgrind and want to  
reduce the noise" config symbol.

(And xclose only actually matters on NFS, no other filesystem can  
return an error from close() that I know of, but as long as it's  
there...)

Rob
 1373605879.0


More information about the Toybox mailing list