Permalink
Browse files

README could have better examples

error case inverts "?" and ":"
reasonable programs loop infinitely on invalid arguments
make JS jsstyle-clean and javascriptlint-clean
fix tests for node 0.6 removal of runtime path modification
  • Loading branch information...
1 parent 1901b5a commit 13f206a086cd5752f237670063b2e1d9489837e5 @davepacheco committed Jun 26, 2012
Showing with 285 additions and 102 deletions.
  1. +185 −72 README.md
  2. +72 −0 examples/basic.js
  3. +7 −7 examples/examples.js
  4. +19 −19 lib/getopt.js
  5. +1 −2 tests/test-getopt.js
  6. +1 −2 tests/test-tokenize-optstr.js
View
257 README.md
@@ -5,14 +5,107 @@ node-getopt
Overview
--------
-node-getopt is a Node.js module providing an interface to the POSIX-defined
-getopt() function, a general-purpose command line parser that follows the POSIX
+node-getopt implements the POSIX getopt() function for Node. getopt() provides
+a functional interface for option parsing.
+
+Install the npm package in the usual way:
+
+ $ npm install posix-getopt
+
+Here's how you'd typically use it for a command that takes options "-a" and
+"-b" with no arguments, option "-o" (also called "--output") with one argument,
+and another mandatory argument:
+
+ var mod_getopt = require('posix-getopt');
+ var parser, option;
+
+ parser = new mod_getopt.BasicParser('abo:(output)', process.argv);
+
+ while ((option = parser.getopt()) !== undefined) {
+ switch (option.option) {
+ case 'a':
+ console.log('option "a" is set');
+ break;
+
+ case 'b':
+ console.log('option "b" is set');
+ break;
+
+ case 'o':
+ console.error('option "o" has value "%s"',
+ option.optarg);
+ break;
+
+ default:
+ /* error message already emitted by getopt */
+ mod_assert.equal('?', option.option);
+ break;
+ }
+ }
+
+ if (parser.optind() >= process.argv.length)
+ usage('missing required argument: "input"');
+
+ console.log('input = %s', process.argv[parser.optind()]);
+
+Examples:
+
+ $ cmd
+ error: missing required argument: "input"
+ usage: cmd [-ab] [-o file] input
+
+ $ cmd foo
+ input = foo
+
+ $ cmd -a foo
+ option "a" is set
+ input = foo
+
+ $ cmd -ba foo
+ option "b" is set
+ option "a" is set
+ input = foo
+
+ $ cmd -ba -obar foo
+ option "b" is set
+ option "a" is set
+ option "o" has value "bar"
+ input = foo
+
+ $ cmd -ba --output=bar foo
+ option "b" is set
+ option "a" is set
+ option "o" has value "bar"
+ input = foo
+
+ $ cmd --output= foo
+ option "o" has value ""
+ input = foo
+
+ $ cmd -o
+ option requires an argument -- o
+ error: missing required argument: "input"
+ usage: cmd [-ab] [-o file] input
+
+ $ cmd -- -a
+ input = -a
+
+ $ cmd -q
+ illegal option -- q
+ error: missing required argument: "input"
+ usage: cmd [-ab] [-o file] input
+
+
+Background
+--------
+
+getopt() is a general-purpose command line parser that follows the POSIX
guidelines for command-line utilities. Using these guidelines encourages
common conventions among applications, including use of:
- o short option names (e.g., "-r")
- o options with arguments (e.g., "-f filename or -ffilename")
- o chaining short option names when options have no arguments (e.g., "-ra")
+- short option names (e.g., "-r")
+- options with arguments (e.g., "-f filename or -ffilename")
+- chaining short option names when options have no arguments (e.g., "-ra")
This implementation mirrors the Solaris getopt() implementation and supports
long option names (e.g., "--recurse"), potentially with values specified using
@@ -35,29 +128,8 @@ The Utility Syntax Guidelines are described here:
Status
------
-This module is considered complete except that
-
- o test coverage is pretty minimal
- o npm install has not been tested
- o the source is not javascriptlint-clean
-
-There are no known bugs, but the module has not been extensively tested.
-
-
-Platforms
----------
-
-This module should work on all platforms that support node.js. The module is
-tested on MacOS X 10.6.5 and OpenSolaris based on build 111b and Illumos build
-147.
-
-
-Installation
-------------
-
-As an npm package, node-getopt is installed in the usual way:
-
- % npm install posix-getopt
+This module is considered complete except that there's minimal automated test
+coverage. There are no known bugs.
API
@@ -80,12 +152,13 @@ option takes an argument and/or a sequence of strings in parentheses
representing long-option aliases for the option name.
Example option strings:
- ':r' Command takes one option with no args: -r
- ':ra' Command takes two option with no args: -r and -a
- ':raf:' Command takes two option with no args: -r and -a
- and a single option that takes an arg: -f
- ':f:(file)' Command takes a single option with an argument: -f
- -f can also be specified as --file
+
+ ':r' Command takes one option with no args: -r
+ ':ra' Command takes two option with no args: -r and -a
+ ':raf:' Command takes two option with no args: -r and -a
+ and a single option that takes an arg: -f
+ ':f:(file)' Command takes a single option with an argument: -f
+ -f can also be specified as --file
The presence of a leading colon in the option string determines the behavior
when an argument is not specified for an option which takes an argument. See
@@ -126,56 +199,56 @@ The following members may also be present:
This function scans "argv" starting at the current value of "optind" and returns
an object describing the next argument based on the following cases:
- o If the end of command line arguments is reached, an undefined value is
- returned. The end of arguments is signified by a single '-' argument, a
- single '--' argument, an argument that's neither an option nor a previous
- option's argument, the end of argv, or an error.
+- If the end of command line arguments is reached, an undefined value is
+ returned. The end of arguments is signified by a single '-' argument, a
+ single '--' argument, an argument that's neither an option nor a previous
+ option's argument, the end of argv, or an error.
- o If an unrecognized command line option is found (i.e. an option character
- not defined in "optstring"), the returned object's "option" member
- is just "?". "optopt" is set to the unrecognized option letter. "error"
- is set to a true value.
+- If an unrecognized command line option is found (i.e. an option character
+ not defined in "optstring"), the returned object's "option" member
+ is just "?". "optopt" is set to the unrecognized option letter. "error"
+ is set to a true value.
- o If a known command line option is found and the option takes no arguments
- then the returned object's "option" member is the option's short name
- (i.e. the single character specifier in "optstring").
+- If a known command line option is found and the option takes no arguments
+ then the returned object's "option" member is the option's short name
+ (i.e. the single character specifier in "optstring").
- o If a known command line option is found and that option takes an argument
- and the argument is also found, then the returned object's "option"
- member is the option's short name and the "optarg" member contains the
- argument's value.
+- If a known command line option is found and that option takes an argument
+ and the argument is also found, then the returned object's "option"
+ member is the option's short name and the "optarg" member contains the
+ argument's value.
- o If a known command line option is found and that option takes an argument
- but the argument is not found, then the returned object's "option" member
- is "?" unless the first character of "optstring" was a colon, in which
- case the "option" member is set to ":". Either way, the "optopt" member
- is set to the option character that caused the error and "error" is set to
- a true value.
+- If a known command line option is found and that option takes an argument
+ but the argument is not found, then the returned object's "option" member
+ is "?" unless the first character of "optstring" was a colon, in which
+ case the "option" member is set to ":". Either way, the "optopt" member
+ is set to the option character that caused the error and "error" is set to
+ a true value.
Departures from POSIX
--------
- o Global state in the C implementation (e.g., optind, optarg, and optopt) is
- encapsulated in the BasicParser object. optind is available as a method
- call on the parser object. optarg and optopt are returned directly by
- getopt().
+- Global state in the C implementation (e.g., optind, optarg, and optopt) is
+ encapsulated in the BasicParser object. optind is available as a method
+ call on the parser object. optarg and optopt are returned directly by
+ getopt().
- o Rather than returning an integer or character, getopt() returns an object
- with the "option" field corresponding to the processed option character
- and possibly the additional "optarg" and "optopt" fields. If an error
- occurs on a particular option, "error" is also set. If an error occurs on
- no particular option or if the end of input is encountered, undefined is
- returned.
+- Rather than returning an integer or character, getopt() returns an object
+ with the "option" field corresponding to the processed option character
+ and possibly the additional "optarg" and "optopt" fields. If an error
+ occurs on a particular option, "error" is also set. If an error occurs on
+ no particular option or if the end of input is encountered, undefined is
+ returned.
- o Long option forms are supported as described above. This introduces an
- additional error case which is where an argument of the form
- --option=value is encountered, where "option" does not take a value.
+- Long option forms are supported as described above. This introduces an
+ additional error case which is where an argument of the form
+ --option=value is encountered, where "option" does not take a value.
- o POSIX starts "optind" at 1, since argv[0] is generally the name of the
- command and options start at argv[1]. This implementation starts "optind"
- at 2, since argv[0] is generally the path to the node binary and argv[1]
- is the path to the script, so options start with argv[2].
+- POSIX starts "optind" at 1, since argv[0] is generally the name of the
+ command and options start at argv[1]. This implementation starts "optind"
+ at 2, since argv[0] is generally the path to the node binary and argv[1]
+ is the path to the script, so options start with argv[2].
Examples
@@ -191,6 +264,12 @@ Examples
while ((option = parser.getopt()) !== undefined && !option.error)
console.error(option);
+outputs:
+
+ { option: 'l' }
+ { option: 'a' }
+
+
### Example 2: invalid option specified
var mod_getopt = require('getopt')
@@ -202,6 +281,13 @@ Examples
console.error(option);
console.error(option);
+outputs:
+
+ { option: 'l' }
+ illegal option -- b
+ { option: '?', optopt: 'b', error: true }
+
+
### Example 3: long options
var mod_getopt = require('getopt')
@@ -212,6 +298,12 @@ Examples
while ((option = parser.getopt()) !== undefined && !option.error)
console.error(option);
+outputs:
+
+ { option: 'l' }
+ { option: 'r' }
+
+
### Example 4: options with arguments
var mod_getopt = require('getopt')
@@ -222,6 +314,13 @@ Examples
while ((option = parser.getopt()) !== undefined && !option.error)
console.error(option);
+outputs:
+
+ { option: 'l' }
+ { option: 'f', optarg: 'filename' }
+ { option: 'd', optarg: 'type' }
+
+
### Example 5: options with missing arguments
var mod_getopt = require('getopt')
@@ -233,6 +332,14 @@ Examples
console.error(option);
console.error(option);
+outputs:
+
+ { option: 'l' }
+ { option: 'a' }
+ option requires an argument -- f
+ { option: '?', optopt: 'f', error: true }
+
+
### Example 6: options specified multiple times
var mod_getopt = require('getopt')
@@ -242,3 +349,9 @@ Examples
['node', 'script', '-l', '-a', '-l']);
while ((option = parser.getopt()) !== undefined && !option.error)
console.error(option);
+
+outputs:
+
+ { option: 'l' }
+ { option: 'a' }
+ { option: 'l' }
View
72 examples/basic.js
@@ -0,0 +1,72 @@
+/*
+ * examples/basic.js: basic example of using node-getopt
+ *
+ * This example parses options for an example command that takes options "a" and
+ * "b" having no arguments, option "o" (with long alias "output") which takes a
+ * mandatory value, and then one mandatory argument. Example valid invocations:
+ *
+ * cmd foo
+ * cmd -a foo
+ * cmd -ab foo
+ * cmd -a -o bar foo
+ * cmd -o bar foo
+ * cmd --output bar foo
+ * cmd --output=bar foo
+ * cmd --output= foo
+ * cmd -- -a (note: "-a" option is NOT set in this case)
+ *
+ * Invalid invocations:
+ *
+ * cmd missing mandatory argument
+ * cmd -o option "-o" requires an argument
+ * cmd -q unknown option "-q"
+ */
+
+var mod_assert = require('assert');
+var mod_getopt = require('..');
+
+function main()
+{
+ var parser, option;
+
+ parser = new mod_getopt.BasicParser('abo:(output)', process.argv);
+
+ while ((option = parser.getopt()) !== undefined) {
+ switch (option.option) {
+ case 'a':
+ console.log('option "a" is set');
+ break;
+
+ case 'b':
+ console.log('option "b" is set');
+ break;
+
+ case 'o':
+ console.error('option "o" has value "%s"',
+ option.optarg);
+ break;
+
+ default:
+ /* error message already emitted by getopt */
+ mod_assert.equal('?', option.option);
+ break;
+ }
+ }
+
+ if (parser.optind() >= process.argv.length)
+ usage('missing required argument: "input"');
+
+ console.log('input = %s', process.argv[parser.optind()]);
+}
+
+function usage(message)
+{
+ if (message)
+ console.error('error: %s', message);
+
+ console.error('usage: %s %s [-ab] [-o file] input',
+ process.argv[0], process.argv[1]);
+ process.exit(2);
+}
+
+main();
View
14 examples/examples.js
@@ -1,39 +1,39 @@
-var mod_getopt = require('getopt')
+var mod_getopt = require('..');
var parser, option;
-console.error("Example 1: simple short options");
+console.error('Example 1: simple short options');
parser = new mod_getopt.BasicParser('la',
['node', 'script', '-l', '-a', 'stuff']);
while ((option = parser.getopt()) !== undefined && !option.error)
console.error(option);
-console.error("Example 2: invalid option specified");
+console.error('Example 2: invalid option specified');
parser = new mod_getopt.BasicParser('la',
['node', 'script', '-l', '-b', 'stuff']);
while ((option = parser.getopt()) !== undefined && !option.error)
console.error(option);
console.error(option);
-console.error("Example 3: long options");
+console.error('Example 3: long options');
parser = new mod_getopt.BasicParser('lar(recurse)',
['node', 'script', '-l', '--recurse', 'stuff']);
while ((option = parser.getopt()) !== undefined && !option.error)
console.error(option);
-console.error("Example 4: options with arguments");
+console.error('Example 4: options with arguments');
parser = new mod_getopt.BasicParser('f:lad:',
['node', 'script', '-l', '-f', 'filename', '-dtype', 'stuff']);
while ((option = parser.getopt()) !== undefined && !option.error)
console.error(option);
-console.error("Example 5: options with missing arguments");
+console.error('Example 5: options with missing arguments');
parser = new mod_getopt.BasicParser('f:la',
['node', 'script', '-l', '-a', '-f']);
while ((option = parser.getopt()) !== undefined && !option.error)
console.error(option);
console.error(option);
-console.error("Example 6: options specified multiple times");
+console.error('Example 6: options specified multiple times');
parser = new mod_getopt.BasicParser('la',
['node', 'script', '-l', '-a', '-l']);
while ((option = parser.getopt()) !== undefined && !option.error)
View
38 lib/getopt.js
@@ -9,25 +9,25 @@
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
- *
+ *
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
+ * SOFTWARE.
*/
var ASSERT = require('assert').ok;
function goError(msg)
{
return (new Error('getopt: ' + msg));
-};
+}
/*
* The BasicParser is our primary interface to the outside world. The
@@ -38,10 +38,10 @@ function goBasicParser(optstring, argv)
{
var ii;
- ASSERT(optstring || optstring === '', "optstring is required");
- ASSERT(optstring.constructor === String, "optstring must be a string");
- ASSERT(argv, "argv is required");
- ASSERT(argv.constructor === Array, "argv must be an array");
+ ASSERT(optstring || optstring === '', 'optstring is required');
+ ASSERT(optstring.constructor === String, 'optstring must be a string');
+ ASSERT(argv, 'argv is required');
+ ASSERT(argv.constructor === Array, 'argv must be an array');
this.gop_argv = new Array(argv.length);
this.gop_options = {};
@@ -51,7 +51,7 @@ function goBasicParser(optstring, argv)
for (ii = 0; ii < argv.length; ii++) {
ASSERT(argv[ii].constructor === String,
- "argv must be string array");
+ 'argv must be string array');
this.gop_argv[ii] = argv[ii];
}
@@ -166,12 +166,12 @@ goBasicParser.prototype.getopt = function ()
/* end of input */
return (undefined);
- arg = this.gop_argv[this.gop_optind];
+ var arg = this.gop_argv[this.gop_optind];
- if (this.gop_subind == 0) {
+ if (this.gop_subind === 0) {
if (arg == '-' || arg === '' || arg[0] != '-')
return (undefined);
-
+
if (arg == '--') {
this.gop_optind++;
this.gop_subind = 0;
@@ -200,19 +200,19 @@ goBasicParser.prototype.getoptShort = function ()
ASSERT(this.gop_subind < arg.length);
chr = arg[this.gop_subind];
- if (!(chr in this.gop_options))
- return (this.errInvalidOption(chr));
-
if (++this.gop_subind >= arg.length) {
this.gop_optind++;
this.gop_subind = 0;
}
+ if (!(chr in this.gop_options))
+ return (this.errInvalidOption(chr));
+
if (!this.gop_options[chr])
return ({ option: chr });
return (this.getoptArgument(chr));
-}
+};
/*
* Implements getopt() for the case where optind/subind point to a long option.
@@ -237,7 +237,7 @@ goBasicParser.prototype.getoptLong = function ()
if (!this.gop_options[chr]) {
if (eq != -1)
return (this.errExtraArg(alias));
-
+
this.gop_optind++; /* eat this argument */
return ({ option: chr });
}
@@ -275,10 +275,10 @@ goBasicParser.prototype.getoptArgument = function (chr)
goBasicParser.prototype.errMissingArg = function (chr)
{
if (this.gop_silent)
- return ({ option: '?', optopt: chr });
+ return ({ option: ':', optopt: chr });
process.stderr.write('option requires an argument -- ' + chr + '\n');
- return ({ option: ':', optopt: chr, error: true });
+ return ({ option: '?', optopt: chr, error: true });
};
goBasicParser.prototype.errInvalidOption = function (chr)
View
3 tests/test-getopt.js
@@ -2,10 +2,9 @@
* Tests getopt() itself.
*/
var mod_path = require('path');
-require.paths.unshift(mod_path.dirname(__dirname) + '/lib');
var mod_sys = require('sys');
-var mod_getopt = require('getopt');
+var mod_getopt = require('..');
var mod_assert = require('assert');
var test_cases = [ {
View
3 tests/test-tokenize-optstr.js
@@ -2,10 +2,9 @@
* Tests internal state of the parser.
*/
var mod_path = require('path');
-require.paths.unshift(mod_path.dirname(__dirname) + '/lib');
var mod_sys = require('sys');
-var mod_getopt = require('getopt');
+var mod_getopt = require('..');
var mod_assert = require('assert');
var test_cases = [ {

0 comments on commit 13f206a

Please sign in to comment.