/*
======================================================================
plugcmd.c

Ernie Wright  01 Jun 05

Process the command line for the SPD plug-in.  The format of the
command line is

   name complexity tessLevel mergePoints [sceneFile]

For example,

   Sphereflake 2 3 1 Scenes\SPD\sphereflake.lws

creates a sphereflake of complexity 2 and tesselation level 3.  Merge
Points is applied, and the scene data is stored in sphereflake.lws.
The scene filename is optional.  If it's omitted, no scene is stored.
====================================================================== */

#include <stdlib.h>
#include <string.h>
#include "lwmod.h"


/*
======================================================================
free_argv()

Free memory allocated by get_argv().
====================================================================== */

static void free_argv( int argc, char **argv )
{
   int i;

   if ( argv ) {
      for ( i = 0; i < argc; i++ )
         if ( argv[ i ] ) free( argv[ i ] );
      free( argv );
   }
}


/*
======================================================================
strdup()

Duplicate a string.  Some C runtimes provide this function, but some
don't.
====================================================================== */

static char *strdup( const char *str )
{
   char *dup;

   if ( !str ) return NULL;
   dup = malloc( strlen( str ) + 1 );
   if ( dup )
      strcpy( dup, str );
   return dup;
}


/*
======================================================================
get_argv()

Tokenize a command line, copying each token into an element of a
string array.  Tokens are separated by one or more spaces.  Arguments
that contain spaces can be enclosed in double quotes.  Characters
inside angle brackets (< and >) are part of a single vector token.
====================================================================== */

static char **get_argv( const char *cmdline, int maxarg, int *argc )
{
   enum { TOK_SKIP, TOK_ADD, TOK_END };
   int ntok = 0, i, j = 0, end, intok = 0, inquote = 0, inbracket = 0, op;
   char buf[ 128 ], **argv;


   argv = calloc( maxarg, sizeof( char * ));
   if ( !argv ) return NULL;

   end = strlen( cmdline );

   for ( i = 0; i < end && ntok < maxarg; i++ ) {
      switch ( cmdline[ i ] )
      {
         case ' ':
            if ( !intok )
               op = TOK_SKIP;
            else if ( inquote || inbracket )
               op = TOK_ADD;
            else
               op = TOK_END;
            break;

         case '"':
            if ( inbracket )
               op = TOK_ADD;
            else if ( inquote ) {
               op = TOK_END;
               inquote = 0;
            }
            else {
               op = TOK_SKIP;
               intok = inquote = 1;
            }
            break;

         case '<':
            if ( inquote )
               op = TOK_ADD;
            else {
               op = TOK_SKIP;
               intok = inbracket = 1;
            }
            break;

         case '>':
            if ( inquote )
               op = TOK_ADD;
            else {
               op = TOK_END;
               inbracket = 0;
            }
            break;

         default:
            op = TOK_ADD;
            break;
      }

      switch ( op )
      {
         case TOK_ADD:
            buf[ j++ ] = cmdline[ i ];
            break;

         case TOK_END:
            buf[ j ] = 0;
            argv[ ntok ] = strdup( buf );
            j = 0;
            intok = 0;
            ++ntok;
            break;

         default:
            break;
      }
   }

   *argc = ntok;
   return argv;
}


/*
======================================================================
parse_cmdline()

Extract SPD parameters from a command line.
====================================================================== */

int parse_cmdline( const char *cmdline, int *spd, int *sf, int *teslvl,
   int *merge, int *savescene, char *filename )
{
   int argc;
   char **argv;

   argv = get_argv( cmdline, 3, &argc );

   if ( argc == 4 || argc == 5 ) {
      *spd = match_spdname( argv[ 0 ] );
      *sf = atoi( argv[ 1 ] );
      *teslvl = atoi( argv[ 2 ] );
      *merge = 0 != atoi( argv[ 3 ] );
      if ( argc == 5 ) {
         *savescene = 1;
         strcpy( filename, argv[ 4 ] );
      }
      else
         *savescene = 0;
   }

   free_argv( argc, argv );
   return (( argc == 4 || argc == 5 )
      && *spd != 0
      && *sf > 0 && *sf <= 20
      && *teslvl > 0 && *teslvl <= 32 );
}
