topical media & game development

talk show tell print

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.