Expand argument string into an array respecting space between special characters.

NOTE: use \\ to escape inner quotes.

@example 'install --dir "/some/path" -f' >> ['install', '--dir', '/some/path', '-f']

@param val the arg string to split to array.
@param match chars when matched ignore spaces withing these chars.
@param safe same as match except these chars will be included in result.
function expandArgs(val, match, safe) {
    if (Array.isArray(val))
        return val.slice(0); // always slice to clone.
    match = match || ['"', "'"];
    safe = safe || ['[', ']', '<', '>'];
    function replacer(p, c) {
        p.a[p.a.length - 1] += c.replace(/\\(.)/, '$1');
    }
    var all = safe.concat(match);
    var result = val.match(/\\?.|^$/g).reduce(function (p, c) {
        if (~all.indexOf(c)) {
            p.quote ^= 1;
            if (~safe.indexOf(c))
                replacer(p, c);
        }
        else if (!p.quote && c === ' ')
            p.a.push('');
        else
            replacer(p, c);
        return p;
    }, { a: [''], e: false }).a;
    return result;
}