// multiword command processing
//   split separate word/values (i.e. tokens) in command line
//   search for cmd in command-table, cmds[], and execute if found
//   test with example command lines

char s [90];        // for sprintf()

// -----------------------------------------------------------------------------
// arrays of tokens (char *) and corresponging values if numeric
// a token in one word of text/numeric

#define MAX_TOKS   10
char * toks [MAX_TOKS];
int    vals [MAX_TOKS];
int    nTok;

char buf [90];      // char buffer when input is const char

// -------------------------------------
// display the current arrays of tokens and values
void tokDisp ()
{
  Serial.println ("  tokDisp:");
  for (int n = 0; n < nTok; n++)  {
    Serial.print ("     ");
    Serial.print (vals [n]);
    Serial.print (' ');
    Serial.println (toks [n]);
  }
}

// -------------------------------------
// locate tokens in provide string, set ptrs in tokens
int tokenize (char *str )
{
  nTok = 0;

  Serial.print ("  tokenize: ");
  Serial.println (str);

  strcpy (buf, str);  // copy possible const char array into char array

  // initially call strtok() with char array, subsequent calls are passed nul
  // continue processing until nul token found
  // attempt to translate all tokens into numberic value
  for (toks [nTok]  = strtok (buf, " "); toks [nTok]; )  {
    vals [nTok]   = atoi (toks [nTok]);
    toks [++nTok] = strtok (NULL, " ");
  }
  return nTok;
}

// -----------------------------------------------------------------------------
// test command functions used to demonstrate processing
void a (char *toks [], int n) {
  Serial.println (" a:");
  tokDisp ();
}
void b (char *toks [], int n) {
  Serial.println (" b:");
  tokDisp ();
}
void c (char *toks [], int n) {
  Serial.println (" c:");
  tokDisp ();
}
void d (char *toks [], int n) {
  Serial.println (" d:");
  tokDisp ();
}

// -------------------------------------
// command table - function ptr and command string
struct Cmd {
  void (*f) (char *tok [], int nTok);
  const char *name;
}
cmds [] = {             // table for above command functions
  { a, "tom" },
  { b, "dick" },
  { c, "harry" },
  { d, "martha" },
};
const int Ncmd = sizeof(cmds) / sizeof(Cmd);

// -------------------------------------
// tokenize command line and search for cmd, 1st token, in cmds []
void processCmd ( char *buf )
{
  Serial.print ("\nprocessCmd: ");
  Serial.println (buf);

  tokenize (buf);

  for (int n = 0; n < Ncmd; n++)  {
    // execute cmd when found and return
    if (! strcmp (cmds [n].name, toks [0]))  {
      cmds [n].f (toks, nTok);
      return;
    }
  }

  // only reached if cmd not found
  Serial.print (" processCmd: unknown cmd ");
  Serial.println (toks [0]);
}

// -----------------------------------------------------------------------------
// define test command lines
char *str [] = {
  (char *)"martha",
  (char *)"tom 1 2 3",
  (char *)"dick xyz",
  (char *)"harry 1 abc 2",
};
const int Nstr = 4;

void setup ()
{
  Serial.begin (115200);
  delay (200);

  // process each test cmd line
  for (int n = 0; n < Nstr; n++)
    processCmd (str [n]);
}

void loop () { }