/*
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.
  
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
  
  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>. 
*/

#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>

char** parse( char* cmdline, int* _argc ) {
  char* *argv;
  char* _argv;
  unsigned long  len;
  char   a;
  unsigned long  i, j;
  unsigned long  argc = 0;

  bool in_QM = false;
  bool in_TEXT = false;
  bool in_SPACE = true;

  len = strlen( cmdline );
  i = ( ( len + 2 ) / 2 ) * sizeof( void* ) + sizeof( void* );

  argv = ( char** )malloc( i + ( len + 2 ) * sizeof( char ) );
  _argv = ( char* )( ( ( unsigned char* ) argv ) + i );
  argv[ 0 ] = _argv;

  i = 0;
  j = 0;

  while( (a = cmdline[i]) ) {
    if( in_QM ) {
      if( a == '\"' ) {
        in_QM = false;
      } else {
        _argv[ j ] = a;
        j++;
      }
    } else {
      switch( a ) {
	      case '\"':
          in_QM = true;
          in_TEXT = true;
          if( in_SPACE ) {
              argv[ argc ] = _argv + j;
              argc++;
          }
          in_SPACE = false;
          break;
	      case ' ':
	      case '\t':
	      case '\n':
	      case '\r':
          if( in_TEXT ) {
            _argv[ j ] = '\0';
            j++;
          }
          in_TEXT = false;
          in_SPACE = true;
          break;
	      default:
          in_TEXT = true;
          if( in_SPACE ) {
              argv[ argc ] = _argv + j;
              argc++;
          }
          _argv[ j ] = a;
          j++;
          in_SPACE = false;
          break;
      }
    }
    i++;
  }
  _argv[ j ] = '\0';
  argv[ argc ] = (void*)0;

  *_argc = argc;
	return( argv );
}