topical media & game development
lib-js-terminal-termlib-parser.js / js
/*
termlib_parser.js v.1.0
command line parser for termlib.js
(c) Norbert Landsteiner 2005
mass:werk - media environments
<http://www.masswerk.at>
you are free to use this parser under the "termlib.js" license.
usage: call "parseLine(this)" from your Terminal handler
parsed args in this.argv
quoting levels per arg in this.argQL (value: quote char)
this.argc: pointer to this.argv and this.argQL (used by parserGetopt)
call parserGetopt(this, "<options>") from your handler to get opts
(returns an object with properties for every option flag. any float
values are stored in Object.<flag>.value; illegal opts in array
Object.illegals)
configuration: you may want to overide the follow objects (or add properties):
parserWhiteSpace: chars to be parsed as whitespace
parserQuoteChars: chars to be parsed as quotes
parserSingleEscapes: chars to escape a quote or escape expression
parserOptionChars: chars that start an option
parserEscapeExpressions: chars that start escape expressions
*/
// chars to be parsed as white space
var parserWhiteSpace = {
' ': true,
'\t': true
}
// chars to be parsed as quotes
var parserQuoteChars = {
'"': true,
"'": true,
'`': true
};
// chars to be parsed as escape char
var parserSingleEscapes = {
'\\': true
};
// chars that mark the start of an option-expression
// for use with parserGetopt
var parserOptionChars = {
'-': true
}
// chars that start escape expressions (value = handler)
// plugin handlers for ascii escapes or variable substitution
var parserEscapeExpressions = {
'%': parserHexExpression
}
function parserHexExpression(termref, pointer, echar, quotelevel) {
/* example for parserEscapeExpressions
params:
termref: ref to Terminal instance
pointer: position in termref.lineBuffer (echar)
echar: escape character found
quotelevel: current quoting level (quote char or empty)
char under pointer will be ignored
the return value is added to the current argument
*/
// convert hex values to chars (e.g. %20 => <SPACE>)
if (termref.lineBuffer.length > pointer+2) {
// get next 2 chars
var hi = termref.lineBuffer.charAt(pointer+1);
var lo = termref.lineBuffer.charAt(pointer+2);
lo = lo.toUpperCase();
hi = hi.toUpperCase();
// check for valid hex digits
if ((((hi>='0') && (hi<='9')) || ((hi>='A') && ((hi<='F')))) &&
(((lo>='0') && (lo<='9')) || ((lo>='A') && ((lo<='F'))))) {
// next 2 chars are valid hex, so strip them from lineBuffer
parserEscExprStrip(termref, pointer+1, pointer+3);
// and return the char
return String.fromCharCode(parseInt(hi+lo, 16));
}
}
// if not handled return the escape character (=> no conversion)
return echar;
}
function parserEscExprStrip(termref, from, to) {
// strip characters from termref.lineBuffer (for use with escape expressions)
termref.lineBuffer =
termref.lineBuffer.substring(0, from) +
termref.lineBuffer.substring(to);
}
function parserGetopt(termref, optsstring) {
// scans argv form current position of argc for opts
// arguments in argv must not be quoted
// returns an object with a property for every option flag found
// option values (absolute floats) are stored in Object.<opt>.value (default -1)
// the property "illegals" contains an array of all flags found but not in optstring
// argc is set to first argument that is not an option
var opts = { 'illegals':[] };
while ((termref.argc < termref.argv.length) && (termref.argQL[termref.argc]=='')) {
var a = termref.argv[termref.argc];
if ((a.length>0) && (parserOptionChars[a.charAt(0)])) {
var i = 1;
while (i<a.length) {
var c=a.charAt(i);
var v = '';
while (i<a.length-1) {
var nc=a.charAt(i+1);
if ((nc=='.') || ((nc>='0') && (nc<='9'))) {
v += nc;
i++;
}
else break;
}
if (optsstring.indexOf(c)>=0) {
opts[c] = (v == '')? {value:-1} : (isNaN(v))? {value:0} : {value:parseFloat(v)};
}
else {
opts.illegals[opts.illegals.length]=c;
}
i++;
}
termref.argc++;
}
else break;
}
return opts;
}
function parseLine(termref) {
// stand-alone parser, takes a Terminal instance as argument
// parses the command line and stores results as instance properties
// argv: list of parsed arguments
// argQL: argument's quoting level (<empty> or quote character)
// argc: cursur for argv, set initinally to zero (0)
// open quote strings are not an error but automatically closed.
var argv = ['']; // arguments vector
var argQL = ['']; // quoting level
var argc = 0; // arguments cursor
var escape = false ; // escape flag
for (var i=0; i<termref.lineBuffer.length; i++) {
var ch= termref.lineBuffer.charAt(i);
if (escape) {
argv[argc] += ch;
escape = false;
}
else if (parserEscapeExpressions[ch]) {
var v = parserEscapeExpressions[ch](termref, i, ch, argQL[argc]);
if (typeof v != 'undefined') argv[argc] += v;
}
else if (parserQuoteChars[ch]) {
if (argQL[argc]) {
if (argQL[argc] == ch) {
argc ++;
argv[argc] = argQL[argc] = '';
}
else {
argv[argc] += ch;
}
}
else {
if (argv[argc] != '') {
argc ++;
argv[argc] = '';
argQL[argc] = ch;
}
else {
argQL[argc] = ch;
}
}
}
else if (parserWhiteSpace[ch]) {
if (argQL[argc]) {
argv[argc] += ch;
}
else if (argv[argc] != '') {
argc++;
argv[argc] = argQL[argc] = '';
}
}
else if (parserSingleEscapes[ch]) {
escape = true;
}
else {
argv[argc] += ch;
}
}
if ((argv[argc] == '') && (!argQL[argc])) {
argv.length--;
argQL.length--;
}
termref.argv = argv;
termref.argQL = argQL;
termref.argc = 0;
}
// eof
(C) Æliens
04/09/2009
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.