Skip to content

Commit

Permalink
Integrated OS.parse.
Browse files Browse the repository at this point in the history
  • Loading branch information
kriskowal committed Mar 1, 2010
1 parent 9542129 commit 0e42a8b
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 57 deletions.
74 changes: 62 additions & 12 deletions lib/os.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@

// -- kriskowal Kris Kowal Copyright (C) 2009-2010 MIT License
// -- penwellr TODO
// contributed "parse"

var engine = require('os-engine');
for (var name in engine) {
Expand Down Expand Up @@ -63,21 +65,49 @@ exports.command = function (command) {
/**
* enquotes a string such that it is guaranteed to be a single
* argument with no interpolated values for a shell.
*
* /!\ WARNING: as yet, this implementation only handles
* enquoting for Unix shell script style arguments. Further
* development is necessary to enquote and escape arguments
* on Windows.
*/
exports.enquote = function (word) {
return "'" + String(word).replace(/'/g, "'\"'\"'") + "'";
};

exports.parse = function (args)
{
var startsWith = function(self, str) { return (self.match("^"+str.replace('\\', '\\\\'))==str) }
var endsWith = function(self, str) { return (self.match(str.replace('\\', '\\\\')+"$")==str) }
/**
* parses command line arguments
* @param command {String} a command composed of space delimited,
* quoted, or backslash escaped arguments.
* @returns an Array of unquoted arguments.
*
* /!\ WARNING: this does not handle all of the edge cases
* of command line argument parsing, nor is suitable for
* general purpose argument enquoting on all platforms. It
* also will never be able to handle environment variable
* interpolation or other forms of shell quote expansion.
* This utility is used by Narwhal to pare arguments from
* system.env.NARWHAL_OPT.
*/
exports.parse = function (args) {
var startsWith = function(self, str) {
return (self.match("^"+str.replace('\\', '\\\\'))==str)
}
var endsWith = function(self, str) {
return (self.match(str.replace('\\', '\\\\')+"$")==str)
}
var results = [], quoteType = null, quotedElement = null;
args.split(' ').forEach(function(element) {
if (quoteType || endsWith(element, '\\') || startsWith(element, '\'') || startsWith(element, '"')) {
if (
quoteType || endsWith(element, '\\') ||
startsWith(element, '\'') || startsWith(element, '"')
) {
if (quoteType) {
if (endsWith(element, quoteType)) {
results.push(quotedElement + " " + element.substring(0, element.length - 1));
results.push(
quotedElement + " " +
element.substring(0, element.length - 1)
);
quotedElement = null;
quoteType = null;
return;
Expand All @@ -96,16 +126,36 @@ exports.parse = function (args)
}
if (!quoteType) {
if (endsWith(element, '\\')) {
if (quotedElement) { quotedElement += " " + element.substring(0, element.length - 1); }
else { quotedElement = element.substring(0, element.length - 1); }
if (quotedElement) {
quotedElement += " " + element.substring(
0,
element.length - 1
);
}
else {
quotedElement = element.substring(
0,
element.length - 1
);
}
}
else {
results.push(quotedElement + ' ' + element);
quotedElement = null;
return;
}
else { results.push(quotedElement + ' ' + element); quotedElement = null; return; }
}
}
else {
if (quotedElement) { results.push(quotedElement+' '+element); quotedElement = null;}
else { results.push(element); }
if (quotedElement) {
results.push(quotedElement + ' ' + element);
quotedElement = null;
}
else {
results.push(element);
}
}
});
return results;
}
};

119 changes: 74 additions & 45 deletions tests/os/parse.js
Original file line number Diff line number Diff line change
@@ -1,68 +1,97 @@
var assert = require("test/assert");
var os = require("os");
var io = require("io");

var ASSERT = require("assert");
var OS = require("os");

// TODO parameterize on whether the system.os is Win(nt|dows).

exports.testNoEscapedPaths = function() {
var result = os.parse('command -option -with other option');
assert.eq(5, result.length);
assert.eq("command", result[0]);
assert.eq("-option", result[1]);
assert.eq("-with", result[2]);
assert.eq("other", result[3]);
assert.eq("option", result[4]);
var result = OS.parse('command -option -with other option');
ASSERT.equal(5, result.length);
ASSERT.equal("command", result[0]);
ASSERT.equal("-option", result[1]);
ASSERT.equal("-with", result[2]);
ASSERT.equal("other", result[3]);
ASSERT.equal("option", result[4]);
};

exports.testSlashEscapedPath = function() {
var result = os.parse('command -path /Volume/path\\ with\\ space/dir');
assert.eq(3, result.length);
assert.eq("command", result[0]);
assert.eq("-path", result[1]);
assert.eq("/Volume/path with space/dir", result[2]);
var result = OS.parse('command -path /Volume/path\\ with\\ space/dir');
ASSERT.equal(3, result.length);
ASSERT.equal("command", result[0]);
ASSERT.equal("-path", result[1]);
ASSERT.equal("/Volume/path with space/dir", result[2]);
};

exports.testSingleQuotedPath = function() {
var result = os.parse("command -path '/Volume/path with space/dir'");
assert.eq(3, result.length);
assert.eq("command", result[0]);
assert.eq("-path", result[1]);
assert.eq("/Volume/path with space/dir", result[2]);
var result = OS.parse("command -path '/Volume/path with space/dir'");
ASSERT.equal(3, result.length);
ASSERT.equal("command", result[0]);
ASSERT.equal("-path", result[1]);
ASSERT.equal("/Volume/path with space/dir", result[2]);
};

exports.testDoubleQuotedPath = function() {
var result = os.parse('command -path "/Volume/path with space/dir"');
assert.eq(3, result.length);
assert.eq("command", result[0]);
assert.eq("-path", result[1]);
assert.eq("/Volume/path with space/dir", result[2]);
var result = OS.parse('command -path "/Volume/path with space/dir"');
ASSERT.equal(3, result.length);
ASSERT.equal("command", result[0]);
ASSERT.equal("-path", result[1]);
ASSERT.equal("/Volume/path with space/dir", result[2]);
};

exports.testQuoteInsideQuote = function() {
var result = os.parse('command -path "/Volume/path with space/dir \'yet more quotes\'"');
assert.eq(3, result.length);
assert.eq("command", result[0]);
assert.eq("-path", result[1]);
assert.eq("/Volume/path with space/dir 'yet more quotes'", result[2]);
var result = OS.parse('command -path "/Volume/path with space/dir \'yet more quotes\'"');
ASSERT.equal(3, result.length);
ASSERT.equal("command", result[0]);
ASSERT.equal("-path", result[1]);
ASSERT.equal("/Volume/path with space/dir 'yet more quotes'", result[2]);
};

exports.testQuotedAndSlashed = function() {
var result = os.parse('command -path "/Volume/path\\ with\\ space/dir"');
assert.eq(3, result.length);
assert.eq("command", result[0]);
assert.eq("-path", result[1]);
assert.eq("/Volume/path\\ with\\ space/dir", result[2]);
var result = OS.parse('command -path "/Volume/path\\ with\\ space/dir"');
ASSERT.equal(3, result.length);
ASSERT.equal("command", result[0]);
ASSERT.equal("-path", result[1]);
ASSERT.equal("/Volume/path\\ with\\ space/dir", result[2]);
};

/* TODO unix sh specific details
exports.testSingleQuoteAndSlash = function () {
var result = OS.parse("'\\'");
ASSERT.equal(result.length, 1);
ASSERT.equal(result[0], '\\');
};
exports.testAdjacentSingleQuotes = function () {
var result = OS.parse("'a''b'");
ASSERT.equal(result.length, 1);
ASSERT.equal(result[0], 'ab');
};
exports.testAdjacentDoubleQuotes = function () {
var result = OS.parse('"a""b"');
ASSERT.equal(result.length, 1);
ASSERT.equal(result[0], 'ab');
};
exports.testAdjacentMixedQuotes = function () {
var result = OS.parse('"a"\'b\'');
ASSERT.equal(result.length, 1);
ASSERT.equal(result[0], 'ab');
};
*/

exports.testAllEscapeTypes = function() {
var result = os.parse('command -path "/Volume/path with space/dir" -I \'/volume/path with space\' -L /volume/libs\\ with\\ space/lib');
assert.eq(result.length, 7);
assert.eq("command", result[0]);
assert.eq("-path", result[1]);
assert.eq("/Volume/path with space/dir", result[2]);
assert.eq("-I", result[3]);
assert.eq("/volume/path with space", result[4]);
assert.eq("-L", result[5]);
assert.eq("/volume/libs with space/lib", result[6]);
var result = OS.parse('command -path "/Volume/path with space/dir" -I \'/volume/path with space\' -L /volume/libs\\ with\\ space/lib');
ASSERT.equal(result.length, 7);
ASSERT.equal("command", result[0]);
ASSERT.equal("-path", result[1]);
ASSERT.equal("/Volume/path with space/dir", result[2]);
ASSERT.equal("-I", result[3]);
ASSERT.equal("/volume/path with space", result[4]);
ASSERT.equal("-L", result[5]);
ASSERT.equal("/volume/libs with space/lib", result[6]);
};

if (require.main == module.id)
os.exit(require("test/runner").run(exports));
OS.exit(require("test").run(exports));

0 comments on commit 0e42a8b

Please sign in to comment.