Right and wrong, getopt-style

I found myself grinning while reading the Mac OS X getopt() man page:

A single dash “-” may be specified as a character in optstring, however it should never have an argument associated with it. This allows getopt() to be used with programs that expect “-” as an option flag. This practice is wrong, and should not be used in any current development.

[…]

It is also possible to handle digits as option letters. This allows getopt() to be used with programs that expect a number (“-3”) as an option. This practice is wrong, and should not be used in any current development.

Yeah!! The eternal war of right against wrong, good against evil, playing out in nasty getopt() extensions.

Of course, Mac OS X getopt() also uses the evil non-standard optreset (although the optind = 0 solution is hardly more elegant). I am hacking around trying to find a way to run getopt() twice in a portable manner without barfing every time I read the code. Current best of breed solutions look something like this:

http://lists.samba.org/archive/samba-technical/2004-May/035795.html

And re: Vonage replacement: I just unplugged the Vonage box for now, which effectively turns it into a really expensive forwarding service.

10 thoughts on “Right and wrong, getopt-style”

  1. Erm… wow. I’m flattered that my two favorite flag sets are considered wrong practices by MacOS X. :-D


    $ dis1600 -?

    DIS-1600 Advanced(?) CP-1600 Disassembler
    Copyright 2003, Joseph Zbiciak
    …snip a bunch of flags…


    Individual analysis phase controls:
    -0 --disable-mark-cart-header Don't try to interpret cart header
    -1 --disable-funky-branch-detect Don't detect non-JSR/J/B branches
    -2 --disable-kill-bad-branches Don't kill branches to invalid ops
    -3 --disable-brtrg-vs-sdbd Branch targets don't affect SDBD
    -4 --disable-find-jsr-data Don't try to find data after JSR
    -5 --disable-invalid-propagation Don't propagate invalid instrs
    -6 --disable-exec-sound-interp Don't interpret EXEC music/sfx
    -7 --disable-exec-print Don't look for EXEC print calls

    …snip remaining flags…

    And lessee… Some other of my self-written utilities follow a tradition established for me by Jef Poskanzer’s venerable NetPBM Toolkit, but seen elsewhere also: “-” in place of a filename specifies stdin or stdout as an input or output file, respectively. That’s incredibly handy!

    As for scanning the flagset multiple times… Perhaps I’m missing an obvious reason why one wouldn’t scan the flagset once into a higher-level representation than argc/argv and just refer to that from everywhere? This is a serious question. I mostly write what many might consider toy programs, so there must be something I’m missing. I also tend to control most of the code that ends up even in my larger programs. Perhaps that’s it?

    Edit: That also reminds me: With my main personal project, I package a copy of the GNU getopt_long so that I don’t have to deal too much with deficiencies on target systems. If they don’t provide the getopt I want, I can just abort to my copy of getopt_long. Is there any serious differentiation you might lose out on by carrying a private copy of getopt? I sincerely hope that parsing argv is not a bottleneck in your program, so that would leave other issues such as localization/internationalization, etc. that some platforms might handle differently than others. (Although, you’ll have to convince me that spelling command line arguments differently based on locale is a wise thing…)

  2. Re: haha nice preachy manpage. just ditch getopt.

    But popt uses StudlyCaps, and I would rather die than use an interface with names like poptGetNextOpt().

  3. Here’s how I do it in e2fsprogs’s debugfs:

    /*
     * This function resets the libc getopt() function, which keeps
     * internal state.  Bad design!  Stupid libc API designers!  No
     * biscuit!
     *
     * BSD-derived getopt() functions require that optind be reset to 1 in
     * order to reset getopt() state.  This used to be generally accepted
     * way of resetting getopt().  However, glibc's getopt()
     * has additional getopt() state beyond optind, and requires that
     * optind be set zero to reset its state.  So the unfortunate state of
     * affairs is that BSD-derived versions of getopt() misbehave if
     * optind is set to 0 in order to reset getopt(), and glibc's getopt()
     * will core dump if optind is set 1 in order to reset getopt().
     *
     * More modern versions of BSD require that optreset be set to 1 in
     * order to reset getopt().   Sigh.  Standards, anyone?
     *
     * We hide the hair here.
     */
    void reset_getopt(void)
    {
    #if defined(__GLIBC__) || defined(__linux__)
    	optind = 0;
    #else
    	optind = 1;
    #endif
    #ifdef HAVE_OPTRESET
    	optreset = 1;		/* Makes BSD getopt happy */
    #endif
    }
    
  4. Umm, it is GPL code. It’s in e2fsprogs’s debugfs. Or did you mean that you needed non-GPL’ed code.

    BTW, are you in a position to accept consulting work at this point? I just sent a company your way….

  5. Sorry – the code I was working on wasn’t GPL, otherwise I would have used yours.

    Depends on the contract work – I’ll talk to Ric. Thanks!

  6. For the record, in the future, for something that small — just ask. I’m very happy to relicense tiny bits of useful code under a BSD license.

Comments are closed.