sh
/* $Id$ */
							/* Copyright (c) 2005-2012 Pierre Pronchery <khorben@defora.org> */
							/* This file is part of DeforaOS Unix sh */
							/* 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, version 3 of the License.
							 *
							 * 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 <sys/types.h>
							#include <sys/wait.h>
							#include <stdlib.h>
							#include <stdio.h>
							#include <string.h>
							#include <signal.h>
							#include "sh.h"
							#include "job.h"
							/* types */
							typedef struct _Job
							{
								char * command;
								pid_t pid;
								JobStatus status;
								int error;
							} Job;
							/* variables */
							static Job * jobs = NULL;
							static unsigned int jobs_cnt = 0;
							/* job_add */
							static int _add_wait(unsigned int id);
							static void _add_wait_all(void);
							int job_add(char * command, pid_t pid, JobStatus status)
							{
								int ret = 0;
								Job * p;
							#ifdef DEBUG
								fprintf(stderr, "DEBUG: %s(%u)\n", __func__, jobs_cnt + 1);
							#endif
								if((command = strdup(command)) == NULL)
									return sh_error("malloc", 1);
								if((p = realloc(jobs, sizeof(*p) * (jobs_cnt + 1))) == NULL)
								{
									free(command);
									return sh_error("malloc", 1);
								}
								jobs = p;
								p = &jobs[jobs_cnt++];
								p->command = command;
								p->pid = pid;
								p->status = status;
								/* FIXME depending on further C-z handling we could do this earlier */
								if(status == JS_WAIT)
									ret = _add_wait(jobs_cnt);
								_add_wait_all();
								return ret;
							}
							static int _job_remove(unsigned int id);
							static int _add_wait(unsigned int id)
							{
								int status;
								for(;;)
									if(waitpid(jobs[id - 1].pid, &status, 0) == -1)
										return sh_error("waitpid", -1);
									else if(WIFEXITED(status) || WIFSIGNALED(status))
										break;
								_job_remove(id);
								return WEXITSTATUS(status);
							}
							static void _job_print(unsigned int id, char c, char * state);
							static void _add_wait_all(void)
							{
								pid_t pid = 0;
								int status;
								unsigned int i;
								while(jobs_cnt > 0 && (pid = waitpid(-1, &status, WNOHANG)) > 0)
								{
									for(i = 0; i < jobs_cnt && jobs[i].pid != pid; i++);
									if(i == jobs_cnt)
										continue;
									_job_print(i + 1, 'X', "FIXME");
									_job_remove(i + 1);
								}
								if(pid == -1)
									sh_error("waitpid", 0);
							}
							/* job_kill_status */
							int job_kill_status(int signum, JobStatus status)
							{
								int ret = 0;
								unsigned int i;
								for(i = 0; i < jobs_cnt; i++)
									if(jobs[i].status == status)
										ret |= kill(jobs[i].pid, signum);
								return ret == 0 ? 0 : 1;
							}
							/* job_remove */
							static int _job_remove(unsigned int id)
							{
								Job * p;
							#ifdef DEBUG
								fprintf(stderr, "DEBUG: %s(%u)\n", __func__, id);
							#endif
								if(id > jobs_cnt)
									return 1;
								if(id > 1)
								{
									free(jobs[id - 1].command);
									memmove(&jobs[id - 1], &jobs[id], (jobs_cnt - id) * sizeof(*p));
									if((p = realloc(jobs, sizeof(*p) * --jobs_cnt)) == NULL
											&& jobs_cnt != 0)
										return sh_error("malloc", 1);
									jobs = p;
								}
								else /* FIXME check this code */
									jobs_cnt--;
								return 0;
							}
							/* job_list */
							int job_list(int argc, char * argv[])
							{
								int i;
								unsigned int j;
								unsigned int id;
								char * p;
								if(argc == 0)
								{
									for(j = 0; j < jobs_cnt; j++)
										_job_print(j+1, 'X', "FIXME");
									return 0;
								}
								for(i = 1; i < argc; i++)
								{
									id = strtol(argv[i], &p, 10);
									if(*(argv[i]) == '\0' || *p != '\0' || id < 1 || id >= jobs_cnt)
										continue;
									_job_print(id+1, 'X', "FIXME");
								}
								return 0;
							}
							/* job_pgids */
							int job_pgids(int argc, char * argv[])
							{
								/* FIXME implement */
								return 1;
							}
							/* job_print */
							static void _job_print(unsigned int id, char c, char * state)
							{
								printf("[%u] %c %s %s\n", id, c, state, jobs[id - 1].command);
							}
							/* job_status */
							int job_status(int argc, char * argv[])
							{
								/* FIXME ? */
								job_list(1, NULL);
								return 1;
							}
							