/* 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;

	pid = fork();
	if (pid == 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;
}