home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume3 / egetopt / README < prev   
Text File  |  1989-02-03  |  7KB  |  195 lines

  1. egetopt.c -- Extended 'getopt'.
  2.  
  3. A while back, a public-domain version of getopt() was posted to the
  4. net.  A bit later, a gentleman by the name of Keith Bostic made some
  5. enhancements and reposted it.
  6.  
  7. In recent weeks (i.e., early-to-mid 1988) there has been a sometimes
  8. heated discussion in comp.lang.c about the merits and drawbacks of
  9. getopt(), especially with regard to its handling of '?'.
  10.  
  11. In light of this, I have taken Mr. Bostic's public-domain getopt()
  12. and have made some changes that I hope will be considered to be
  13. improvements.  I call this routine 'egetopt' ("Extended getopt").
  14. The default behavior of this routine is the same as that of getopt(),
  15. but it has some optional features that make it more useful.  These
  16. options are controlled by the settings of some global variables.
  17. By not setting any of these extra global variables, you will have
  18. the same functionality as getopt(), which should satisfy those
  19. purists who believe getopt() is perfect and can never be improved.
  20. If, on the other hand, you are someone who isn't satisfied with the
  21. status quo, egetopt() may very well give you the added capabilities
  22. you want.
  23.  
  24. egetopt() behaves like getopt() with the following added capabilities:
  25.  
  26. --    The '?' which gets returned when there is an unrecognized option
  27.     is now stored in a global integer called 'optbad', and the caller
  28.     can set this value to anything.  The initial value in 'optbad' is
  29.         '?', which means that the default behavior is just like that of
  30.         getopt().  For example, If you want egetopt() to return '~'
  31.         instead of '?' when it sees an invalid option, put the following
  32.         lines in your code before egetopt() gets called:
  33.  
  34.         extern int optbad;
  35.         optbad = (int)'~';
  36.  
  37. --    Options can begin with characters other than just '-'.  There
  38.     is now a global character pointer called 'optstart'.  It points
  39.     to a string which consists of a list of characters which can
  40.     be used to begin options.  The initial string that 'optstart'
  41.     points to is "-", so the default behavior is like that of
  42.         getopt().  For example, if you want to allow both '+' and '-'
  43.         as option delimiters, put the following lines in your code
  44.         before egetopt() gets called:
  45.  
  46.         extern char *optstart;
  47.         optstart = "-+";
  48.  
  49. --    Now that there's a choice of the characters that can precede options
  50.     it's desirable to let the caller know what character begins a
  51.     given option.  In egetopt(), the global integer 'optchar' will
  52.     now contain the character that begins a given option, or 0 if
  53.     there was an error.  Just put the following line in your code
  54.     and you can check the value of 'optchar' after each call to
  55.     egetopt():
  56.  
  57.         extern int optchar;
  58.  
  59. --    The old getopt() writes error messages to file descriptor 2
  60.     (or to stderr, depending on your implementation).  In egetopt(),
  61.     you can change this file descriptor to be anything you want.
  62.     The global integer 'opterrfd' contains the file descriptor
  63.     to use for writing error messages.  As you might have guessed,
  64.     this variable is initialized to 2.  As an example, if you want
  65.     your egetopt() errors to go to the file "egetopt.errs", do
  66.         something similar to the following before calling egetopt():
  67.  
  68.         extern int opterrfd;
  69.  
  70.         FILE *eout = fopen("egetopt.errs", "w");
  71.  
  72.         if (eout == (FILE)NULL) {
  73.             /* error condition/
  74.             ...
  75.             exit(1);
  76.         }
  77.  
  78.         opterrfd = fileno(eout);
  79.  
  80. --    Some implementations of getopt() allow you to set the global
  81.     integer 'opterr' to control whether error output is printed:
  82.     it is initialized to 1, which enables error output (as does
  83.     any non-zero value); setting it to 0 disables error output.
  84.     In egetopt(), 'opterr' is treated the same way.
  85.  
  86. --    The old getopt() forces you to use ':' in the string of option
  87.     letters to show that a given option takes an argument.  There is
  88.     now a global integer called 'optneed' which contains this value,
  89.     so you can change it to something else if you want.  As you might
  90.         have suspected, 'optneed' is initialized to ':'.
  91.  
  92.     In addition, something that I always found annoying about the old
  93.     getopt() is its inability to handle non-mandatory option arguments.
  94.     For example, if an option called 'd' was specified as taking
  95.     an argument to the program 'foo', you'd get the following
  96.     results when invoking 'foo' in different ways:
  97.  
  98.     1)    foo -dABC -x ...
  99.  
  100.             getopt() return:    'd'
  101.             optarg:            "ABC"
  102.  
  103.     2)    foo -dABC -x ...
  104.  
  105.             getopt() return:    'd'
  106.             optarg:            "ABC"
  107.  
  108.     3)    foo -d -x ...
  109.  
  110.         A)    getopt() return:    'd'
  111.             optarg:            "-x"
  112.  
  113.     In the case of number 3, sometimes one would prefer to get ...
  114.  
  115.         B)    getopt() return:    'd'
  116.             optarg:            NULL
  117.  
  118.     This would allow "-x" to be handled as another option in the next
  119.     call.  In the old getopt(), you can get the 3B behavior by testing
  120.     the first character of 'optarg' and decrementing 'optind' if this
  121.     character is '-'.  However, since I am enhancing the routine
  122.         anyway, I decided to build in the ability to have either the 3A
  123.         or the 3B behavior.
  124.  
  125.     Since this behavior isn't always desired, I have added another
  126.     global integer called 'optmaybe' which optionally allows you to
  127.     control whether an option with an argument will get treated as number
  128.     3A or as number 3B above.  It is used similarly to 'optneed'.  It is
  129.     initialized to 0, meaning that behavior 3B is impossible in the
  130.     default case.  The following example shows how 'optneed' and
  131.     'optmaybe' can be used:
  132.  
  133.                 extern int optneed;
  134.                    extern int optmaybe;
  135.  
  136.                 optneed = (int)'!';    /* use '!' instead of ':'/
  137.         optmaybe = (int)'%';    /* use '%' for optional arguments/
  138.  
  139.         ...
  140.  
  141.         while ((c = egetopt(argc, argv, "abc!d%x")) != EOF) ...
  142.  
  143.     In this example, options 'a', 'b', and 'x' take no arguments,
  144.     option 'c' takes a mandatory argument, and option 'd' takes
  145.     a non-mandatory argument.  If this is contained in program 'foo',
  146.         you'll get the following behavior when you run it:
  147.  
  148.         foo -a -cABC -dXYZ -d -x -c -b ...
  149.  
  150.             egetopt() return:    'a'
  151.             optarg:            NULL
  152.  
  153.             egetopt() return:    'c'
  154.             optarg:            "ABC"
  155.  
  156.             egetopt() return:    'd'
  157.             optarg:            "XYZ"
  158.  
  159.     >>>>>>>>>>    egetopt() return:    'd'
  160.     >>>>>>>>>>    optarg:            NULL
  161.     >> NOTE >>
  162.     >>>>>>>>>>    egetopt() return:    'x'
  163.     >>>>>>>>>>    optarg:            NULL
  164.  
  165.             egetopt() return:    'c'
  166.             optarg:            "-b"
  167.  
  168.             ...
  169.  
  170.     Remember that 'optneed' is initialized to ':' and 'optmaybe'
  171.     is initialized to 0.  This causes behavior identical to that
  172.     of getopt() unless you specifically override it.
  173.  
  174. Since the default behavior of egetopt() is the same as that of getopt(),
  175. there is no reason why you can't rename this routine to getopt() and
  176. use it in place of the original.  I gave it a new name so as not to
  177. offend those of you who believe that getopt() is perfect and should
  178. never have any new features added to it.
  179.  
  180. The code was originally posted to the net as getopt.c by ...
  181.  
  182.     Keith Bostic
  183.     ARPA: keith@seismo 
  184.     UUCP: seismo!keith
  185.  
  186. Current version: added enhancements and comments, reformatted code.
  187.  
  188.     Lloyd Zusman
  189.     Master Byte Software
  190.     Los Gatos, California
  191.     Internet:    ljz@fx.com
  192.     UUCP:        ...!ames!fxgrp!ljz
  193.  
  194.         May, 1988
  195.