docs: function(csv, options) {
          // cache settings
          var separator = options.separator;
          var delimiter = options.delimiter;
  
          // set initial state if it's missing
          if(!options.state.rowNum) {
            options.state.rowNum = 1;
          }
  
          // clear initial state
          var entries = [];
          var state = 0;
          var entry = '';
          var exit = false;
  
          function endOfLine() {          
            // reset the state
            state = 0;
            
            // if 'start' hasn't been met, don't output
            if(options.start && options.state.rowNum < options.start) {
              // update global state
              entry = '';
              options.state.rowNum++;
              return;
            }
            
            if(options.onParseEntry === undefined) {
              // onParseEntry hook not set
              entries.push(entry);
            } else {
              var hookVal = options.onParseEntry(entry, options.state); // onParseEntry Hook
              // false skips the row, configurable through a hook
              if(hookVal !== false) {
                entries.push(hookVal);
              }
            }
  
            // cleanup
            entry = '';
  
            // if 'end' is met, stop parsing
            if(options.end && options.state.rowNum >= options.end) {
              exit = true;
            }
            
            // update global state
            options.state.rowNum++;
          }
  
          // escape regex-specific control chars
          var escSeparator = RegExp.escape(separator);
          var escDelimiter = RegExp.escape(delimiter);
  
          // compile the regEx str using the custom delimiter/separator
          var match = /(D|S|\n|\r|[^DS\r\n]+)/;
          var matchSrc = match.source;
          matchSrc = matchSrc.replace(/S/g, escSeparator);
          matchSrc = matchSrc.replace(/D/g, escDelimiter);
          match = RegExp(matchSrc, 'gm');
          
          // put on your fancy pants...
          // process control chars individually, use look-ahead on non-control chars
          csv.replace(match, function (m0) {
            if(exit) {
              return;
            }
            switch (state) {
              // the start of a value/entry
              case 0:
                // null value
                if (m0 === separator) {
                  entry += m0;
                  state = 0;
                  break;
                }
                // opening delimiter
                if (m0 === delimiter) {
                  entry += m0;
                  state = 1;
                  break;
                }
                // end of line
                if (m0 === '\n') {
                  endOfLine();
                  break;
                }
                // phantom carriage return
                if (/^\r$/.test(m0)) {
                  break;
                }
                // un-delimit value
                entry += m0;
                state = 3;
                break;
  
              // delimited input
              case 1:
                // second delimiter? check further
                if (m0 === delimiter) {
                  entry += m0;
                  state = 2;
                  break;
                }
                // delimited data
                entry += m0;
                state = 1;
                break;
  
              // delimiter found in delimited input
              case 2:
                // escaped delimiter?
                var prevChar = entry.substr(entry.length - 1);
                if (m0 === delimiter && prevChar === delimiter) {
                  entry += m0;
                  state = 1;
                  break;
                }
                // end of value
                if (m0 === separator) {
                  entry += m0;
                  state = 0;
                  break;
                }
                // end of line
                if (m0 === '\n') {
                  endOfLine();
                  break;
                }
                // phantom carriage return
                if (m0 === '\r') {
                  break;
                }
                // broken paser?
                throw new Error('CSVDataError: Illegal state [Row:' + options.state.rowNum + ']');
  
              // un-delimited input
              case 3:
                // null value
                if (m0 === separator) {
                  entry += m0;
                  state = 0;
                  break;
                }
                // end of line
                if (m0 === '\n') {
                  endOfLine();
                  break;
                }
                // phantom carriage return
                if (m0 === '\r') {
                  break;
                }
                // non-compliant data
                if (m0 === delimiter) {
                  throw new Error('CSVDataError: Illegal quote [Row:' + options.state.rowNum + ']');
                }
                // broken parser?
                throw new Error('CSVDataError: Illegal state [Row:' + options.state.rowNum + ']');
              default:
                // shenanigans
                throw new Error('CSVDataError: Unknown state [Row:' + options.state.rowNum + ']');
            }
            //console.log('val:' + m0 + ' state:' + state);
          });
  
          // submit the last entry
          // ignore null last line
          if(entry !== '') {
            endOfLine();
          }
  
          return entries;
        }