/* dock.c- built-in Dock module for WindowMaker

 *  WindowMaker window manager
 * 
 *  Copyright (c) 1997 Alfredo K. Kojima
 * 
 *  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 2 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, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <stdlib.h>
#include <string.h>
#include "list.h"
#include "misc.h"

/*
 *----------------------------------------------------------------------
 * parse_command--
 *      Divides a command line into a argv/argc pair.
 *---------------------------------------------------------------------- 
 */
#define PRC_ALPHA	0
#define PRC_BLANK	1
#define PRC_ESCAPE	2
#define PRC_DQUOTE	3
#define PRC_EOS		4
#define PRC_SQUOTE	5

typedef struct
  {
    short nstate;
    short output;
  }
DFA;


static DFA mtable[9][6] =
{
  {
    {3, 1},
    {0, 0},
    {4, 0},
    {1, 0},
    {8, 0},
    {6, 0}},
  {
    {1, 1},
    {1, 1},
    {2, 0},
    {3, 0},
    {5, 0},
    {1, 1}},
  {
    {1, 1},
    {1, 1},
    {1, 1},
    {1, 1},
    {5, 0},
    {1, 1}},
  {
    {3, 1},
    {5, 0},
    {4, 0},
    {1, 0},
    {5, 0},
    {6, 0}},
  {
    {3, 1},
    {3, 1},
    {3, 1},
    {3, 1},
    {5, 0},
    {3, 1}},
  {
    {-1, -1},
    {0, 0},
    {0, 0},
    {0, 0},
    {0, 0},
    {0, 0}},			/* final state */
  {
    {6, 1},
    {6, 1},
    {7, 0},
    {6, 1},
    {5, 0},
    {3, 0}},
  {
    {6, 1},
    {6, 1},
    {6, 1},
    {6, 1},
    {5, 0},
    {6, 1}},
  {
    {-1, -1},
    {0, 0},
    {0, 0},
    {0, 0},
    {0, 0},
    {0, 0}},			/* final state */
};

char * next_token (char *word, char **next)
{
  char *ptr;
  char *ret, *t;
  int state, ctype;

  t = ret = malloc (strlen (word) + 1);
  ptr = word;

  state = 0;
  *t = 0;
  while (1)
    {
      if (*ptr == 0)
	ctype = PRC_EOS;
      else if (*ptr == '\\')
	ctype = PRC_ESCAPE;
      else if (*ptr == '"')
	ctype = PRC_DQUOTE;
      else if (*ptr == '\'')
	ctype = PRC_SQUOTE;
      else if (*ptr == ' ' || *ptr == '\t')
	ctype = PRC_BLANK;
      else
	ctype = PRC_ALPHA;

      if (mtable[state][ctype].output)
	{
	  *t = *ptr;
	  t++;
	  *t = 0;
	}
      state = mtable[state][ctype].nstate;
      ptr++;
      if (mtable[state][0].output < 0)
	{
	  break;
	}
    }

  if (*ret == 0)
    t = NULL;
  else
    t = strdup (ret);

  free (ret);

  if (ctype == PRC_EOS)
    *next = NULL;
  else
    *next = ptr;

  return t;
}


extern void parse_command (char *command, char ***argv, int *argc)
{
  LinkedList *list = NULL;
  char *token, *line;
  int count, i;

  line = command;
  do
    {
      token = next_token (line, &line);
      if (token)
	{
	  list = list_cons (token, list);
	}
    }
  while (token != NULL && line != NULL);

  count = list_length (list);
  *argv = malloc (sizeof (char *) * count);
  i = count;
  while (list != NULL)
    {
      (*argv)[--i] = list->head;
      list_remove_head (&list);
    }
  *argc = count;
}

extern pid_t execCommand (char *command)
{
  pid_t pid;
  char **argv;
  int argc;

  parse_command (command, &argv, &argc);

  if (argv == NULL)
    {
      return 0;
    }

  if ((pid = fork ()) == 0)
    {
      char **args;
      int i;

      args = malloc (sizeof (char *) * (argc + 1));
      if (!args)
	exit (10);
      for (i = 0; i < argc; i++)
	{
	  args[i] = argv[i];
	}
      args[argc] = NULL;
      execvp (argv[0], args);
      exit (10);
    }
  return pid;
}
